Dr Imed ABBASSI 28/02/2019
Institut Supérieur d'Informatique et de Mathématiques de
Monastir (ISIMM)
Support du cours de
JAVA avancé
M. ABBASSI Imed
Enseignant chercheur à ISIMM
LR-OASIS, Université de Tunis El Manar, Tunis
[Link]@[Link]
À propos du cours
Objectifs:
• Les collections
• Les Threads
• Les classes internes et anonymes
• Les interface graphique (GUI)
• Accès aux BDD en java
Prérequis: maîtriser les concepts fondamentaux de Java (
classes et objets, classes abstraites, héritage, les
exceptions et la généricité).
Bibliographie:
1. C. Delannoy, Programmer en Java, Eyrolles, 2014.
2. Luc GERVAIS, Apprendre la programmation orientée objet avec le
langage Java, édition ENI.
Groupe: CPI2-ISIMM 1
Dr Imed ABBASSI 28/02/2019
Contenu du cours
1. Les collections
2. Les Threads
3. Les classes internes et anonymes
4. Les interfaces graphiques
5. Accès aux BDD en java
Chapitre 1: Les collections
1. Introduction
2. Concepts généraux
3. Listes chaînées
4. Les vecteurs dynamiques
5. Les ensembles
6. Queues et deques
7. Tables associatives
Groupe: CPI2-ISIMM 2
Dr Imed ABBASSI 28/02/2019
Introduction
• La plate-forme Java inclut un Framework de
collections.
• Ce Framework est un ensemble des classes et
d’interfaces utiles pour la manipulation des
collections. C’est le package « [Link] ».
• Une collection est un objet représentant un groupe
d'objets (telle que la classe Vector classique).
• La structure des collections est définie de manière
générique:
Introduction
Quatre types principaux de collections:
1. List: collection ordonnée d'éléments qui accepte les
doublons.
2. Set: collection d'éléments non ordonnés par défaut qui
n'accepte pas les doublons.
3. Map: collection sous la forme d'une association de
paires clé/valeur.
4. Queue et Deque: collections qui désignent des files
d’attente.
Groupe: CPI2-ISIMM 3
Dr Imed ABBASSI 28/02/2019
Introduction
• Hiérarchie d’interfaces de collections:
Concepts généraux
• Depuis le JDK 5.0, les collections sont manipulées
par le biais de classes génériques implémentant
l’interface Collection<E>;
• Tous les éléments d’une même collection sont donc
de même type E;
• Par exemple, à une liste chaînée LinkedList<String>,
on ne pourra pas ajouter des éléments de type
Integer ou Point.
• Avant le JDK 5.0, les collections (qui implémentent
alors l’interface Collection) peuvent contenir des
éléments d’un type objet quelconque.
Groupe: CPI2-ISIMM 4
Dr Imed ABBASSI 28/02/2019
Concepts généraux: itérateurs
Définition: Un itérateur est un objet qui permet de «
parcourir » un par un les différents éléments d’une
collection.
• On distingue deux types d’itérateurs:
– Monodirectionnels: le parcours de collection se fait toujours
dans une seule sens du début vers la fin.
– Bidirectionnels: le parcours peut se faire dans les deux sens.
On peut avancer ou reculer.
Itérateurs monodirectionnels: Iterator<E>
• Chaque classe collection dispose d’une méthode iterator
fournissant un itérateur monodirectionnel.
• Syntaxe de création: collection c d’objets de type E.
Iterator[<E>] iter = [Link] () ;
Concepts généraux: itérateurs
• Méthodes de manipulation:
– boolean hasNext(): renvoie true si l'itérateur a encore d'élément
à parcourir, et false sinon. Cette méthode peut déclencher une
exception de type NoSuchElementException.
– E next(): retourne l’objet suivant de collection. Ainsi deux appels
successifs de next fournissent deux objets consécutifs.
– default void remove(): supprime le dernier objet renvoyé par
next de collection. Cette méthode est optionnelle et peut
déclencher une exception de type IllegalStateException.
• On notera bien que l’interface Iterator ne comporte pas
de méthode d’ajout d’un élément à une position donnée.
• Cet ajout n’est réalisable que sur des collections
disposant un itérateur permettant de localiser les
éléments, suivant et précédent, d’un élément donné.
10
Groupe: CPI2-ISIMM 5
Dr Imed ABBASSI 28/02/2019
Concepts généraux: itérateurs
• La boucle for... each permet de simplifier le parcours
d’une collection c<E>, en procédant ainsi:
for (E e : c){ . . . }
Itérateurs bidirectionnels: ListIterator<E>
• Certaines collections (listes chaînées, vecteurs
dynamiques) disposent d’une méthode listIterator qui
fournit un itérateur bidirectionnel.
• Il s’agit, cette fois, d’objet d’un type implémentant
l’interface ListIterator<E> (dérivée de Iterator<E>).
• Syntaxe de création: collection c d’objets de type E.
ListIterator<E> iter = [Link]([indice_debut]);
11
Concepts généraux: itérateurs
• La méthode listIterator peut déclencher une exception de
type IndexOutOfBoundsException dans le cas où la
valeur du paramètre indice_début est négative ou
strictement supérieur à la taille de collection.
• Méthodes de manipulation:
– boolean hasNext()/hasPrevious(): renvoie vrai s'il existe dans
la liste un élément suivant/précédent à parcourir, et false sinon.
– int nextIndex()/previousIndex(): renvoie l'index suivant/
précédent de l'élément courant de la liste.
– E previous()/next(): Renvoie l'élément précédent/suivant dans la
liste et déplace la position du curseur vers l'arrière/avant.
– default void add(E e): Insère l'élément spécifié dans la liste.
– default void remove(): Supprime de la liste le dernier élément
renvoyé par next() ou previous()
– default void set(E e): Remplace le dernier élément renvoyé par
next() ou previous() par l'élément spécifié.
12
Groupe: CPI2-ISIMM 6
Dr Imed ABBASSI 28/02/2019
Concepts généraux: opérations
Construction: toute classe collection C<E> dispose de
plusieurs constructeurs.
C<E> c1 = new C<E>() ; // C c = new C () ; <-- avant JDK 5.0
C<E> c2 = new C<E> (c1) ;// C c2 = new C (c) ; <-- avant JDK 5.0
• Avant le JDK 5.0, aucun contrôle n’était réalisé à la
compilation concernant les types respectifs des éléments
de c2 et de c1.
• Dans ce cas, les éléments de c1 et c2 peuvent être
hétérogènes.
• Depuis le JDK 5.0, le type des éléments de c1 doit être
compatible (identique ou dérivé) avec celui des éléments
de c2.
13
Concepts généraux: opérations
Opérations de base: applicables sur toutes les collections et
peuvent être obligatoires ou facultatives.
• int size(): retourne la taille de collection.
• boolean isEmpty(): retourne true si la collection est vide, et false
sinon.
• boolean add(E e): retourne true si l’ajout d’un élément e à la
collection est effectué, et false sinon.
• boolean contains( E e): retourne true si la collection contient un
élément e, et false sinon.
• boolean remove(E e): retourne true si la suppression d’un
élément e de collection est effectué, et false sinon.
• String toString(): convertit la collection en une chaine de
caractères.
• Object[] toArray(): permet de créer un tableau usuel d’objets à
partir de collection.
14
Groupe: CPI2-ISIMM 7
Dr Imed ABBASSI 28/02/2019
Concepts généraux: opérations
• int hashCode(): retourne le code de hachage calculé pour la
collection.
• Iterator iterator(): retourne un objet itérateur sur la collection.
Opérations collectives (optionnelles): Toute collection c
dispose des méthodes suivantes recevant en argument une
autre collection:
• boolean addAll (Collection<? extends E> ca): ajoute à la
collection c tous les éléments de ca.
• boolean removeAll (Collection<?> ca): supprime de la collection
c tout élément apparaissant égal à un des éléments de ca.
• boolean retainAll (Collection<?> ca): supprime de la collection c
tout élément qui n’apparaît pas égal à un des éléments de ca.
On ne conserve dans c que les éléments de ca.
• void clear(): supprime tous les éléments de collection c.
15
Listes chaînées
LinkedList<E>: permet de manipuler des listes
doublement chaînées.
• Cette classe est très complète puisqu’elle implémente les
interfaces Iterable, Collection, List, Deque, Queue.
• Elle permet des ajouts ou des suppressions à une
position donnée avec une efficacité en O(1).
• L’accès à un élément en fonction de sa valeur ou de sa
position dans la liste sera peu efficace puisqu’il
nécessitera obligatoirement de parcourir une partie de la
liste.
• L’efficacité sera donc en moyenne en O(N).
16
Groupe: CPI2-ISIMM 8
Dr Imed ABBASSI 28/02/2019
Listes chaînées
Construction et parcours:
• Comme toute collection, une liste peut être construite vide
ou à partir d’une autre collection c:
LinkedList<E> list1 = new LinkedList<E> () ;
LinkedList<E> list2 = new LinkedList<E> (c) ;
• Une liste chainée peut être parcourue à l’aide d’un itérateur
bidirectionnel de type ListIterator.
Opérations de modification:
• boolean offer(E e)/add(E e): insère d'un élément e dans la liste.
• boolean add(int i, E e): insère d'un élément e en position i.
• boolean offerFirst(E e): insère un élément e au début de la liste.
• boolean offerLast(E e): insère un élément e à la fin de la liste.
• void addFirst( E e): insère un élément e au début de la liste.
17
Listes chaînées
• void addLast(E e): insère un élément e en fin de la liste.
• boolean addAll(int i, Collection<? extends E> c): insère les
éléments de collection c dans la liste en position i.
• boolean addAll(Collection<? extends E> c): insère les éléments
de collection c à la fin de la liste.
• E remove(): supprime et renvoie le premier élément de la liste
• E set(int i,E e): remplace la valeur du nième élément de la liste
par e.
• E poll(): supprime et renvoie le premier élément de la liste, ou null
si celle-ci est vide.
• boolean remove(E e): supprime l’élément e de la liste.
• E remove(int i): récupère et supprime l’élément à la position i.
• E removeFirst()/removeLast(): récupère et supprime le
premier/dernier élément de la liste.
18
Groupe: CPI2-ISIMM 9
Dr Imed ABBASSI 28/02/2019
Listes chaînées
• E pollFirst()/pollLast(): renvoie le premier/dernier élément de la
liste, ou null en cas de liste vide.
Opérations de consultation:
• int indexOf (e): détermine le premier rang de e dans la liste.
• int lastIndexOf(e): détermine le dernier rang de e dans la liste.
• E peekFirst()/peekLast(): renvoie le premier/dernier élément en
laissant celui-ci dans la liste.
• E get(int i): renvoie l’élément à la position i de la liste.
• getFirst()/getLast(): renvoie le premier/dernier élément de la liste.
19
Listes chaînées
Exemple 1:.
import [Link].*;
public class TestLinkedList {
public static void main(String args[]){
LinkedList<String> list = new LinkedList<String>();
[Link]("Java");
[Link]("C++");
[Link]("C#");
[Link]("C");
[Link](2,"Python");
[Link](list);
[Link]("C++");
[Link](3);
[Link](); [Link]();
[Link](list);
}
}
20
Groupe: CPI2-ISIMM 10
Dr Imed ABBASSI 28/02/2019
Vecteurs dynamiques
ArrayList<E>: permet de manipuler des listes
doublement chaînées ayant une représentation
contiguë. Ici, ces listes sont des vecteurs dynamiques.
• Bien qu’elle implémente l’interface List, la mise en œuvre
de cette classe est différente et prévue pour permettre des
accès efficaces à un élément de rang donné, c’est-à-dire
en O(1).
• Elle offre plus de souplesse que les tableaux d’objets dans
la mesure où sa taille peut varier au fil de l’exécution.
• Mais pour que l’accès direct à un élément de rang donné
soit possible, il est nécessaire que les emplacements les
références des objets soient contigus en mémoire (à la
manière de ceux d’un tableau).
21
Vecteurs dynamiques
Construction et parcours:
• Comme toute collection, un vecteur peut-être construit vide
ou à partir d’une autre collection c:
ArrayList<E> v1 = new ArrayList () ;
ArrayList<E> v2 = new ArrayList(c) ;
ArrayList<E> v3= new ArrayList(initialCapacity);
• Un vecteur peut être parcouru de la même façon que les
listes chainées (LinkedList).
Opérations de modification:
• boolean add(E e): insère d'un élément e à la fin du vecteur.
• boolean add(int i, E e): insère d'un élément e en position i.
• boolean addAll(int i, Collection<? extends E> c): insère les
éléments de collection c dans le vecteur en position i.
22
Groupe: CPI2-ISIMM 11
Dr Imed ABBASSI 28/02/2019
Vecteurs dynamiques
• boolean addAll(Collection<? extends E> c): insère les éléments
de collection c à la fin du vecteur.
• boolean remove(Object o): supprime si possible l’objet o du
vecteur.
• E remove(int i): supprime et retourne l’élément à la position i du
vecteur la liste.
• E set(int i,E e): remplace la valeur du nième élément du vecteur
par e.
Opérations de consultation:
• int indexOf (e): détermine le premier rang de e dans le vecteur.
• int lastIndexOf(e): détermine le dernier rang de e dans le
vecteur.
• E get(int i): renvoie l’élément à la position i du vecteur.
23
Vecteurs dynamiques
Gestion de l’emplacement d’un vecteur:
• void ensureCapacity (capaciteMini):demande d’allouer au
vecteur une capacité au moins égale à capaciteMini ; si la
capacité est déjà supérieure, l’appel n’aura aucun effet.
• void trimToSize(): demande de ramener la capacité du vecteur à
sa taille actuelle en libérant les emplacements mémoire non
utilisés;
Exemple 2:
import [Link].* ;
public class TestArray{
public static void main (String args[]){
ArrayList <Integer> v = new ArrayList <Integer> () ;
[Link] ("En A : taille de v = " + [Link]() ) ;
/* on ajoute 10 objets de type Integer */
for (int i=0 ; i<10 ; i++) [Link] (new Integer(i)) ;
[Link] ("En B : taille de v = " + [Link]() ) ;
24
Groupe: CPI2-ISIMM 12
Dr Imed ABBASSI 28/02/2019
Vecteurs dynamiques
/* affichage du contenu, par acces direct (get) a chaque element */
[Link] ("En B : contenu de v = ") ;
for (Integer e : v) [Link] (e + " ") ;
[Link] () ;
/* suppression des elements de position donnee */
[Link] (3) ;
[Link] (5) ;
[Link] (5) ;
[Link] ("En C : contenu de v = " + v) ;
/* ajout d’elements a une position donnee */
[Link] (2, new Integer (100)) ;
[Link] (2, new Integer (200)) ;
[Link] ("En D : contenu de v = " + v) ;
/* modification d’elements de position donnee */
[Link] (2, new Integer (1000)); // modification element de rang 2
[Link] (5, new Integer (2000)); // modification element de rang 5
[Link] ("En D : contenu de v = " + v) ;
}
}
25
Ensembles
• Deux classes implémentent l’interface Set<E>:
– TreeSet<E>: les éléments sont rangés de manière ascendante.
– HashSet<E>: les éléments sont rangés suivant une méthode de
hachage.
Construction et parcours:
• Comme toute collection, un ensemble peut être construit
vide ou à partir d’une autre collection.
// ensemble vide
HashSet<E> e1 = new HashSet<E> () ;
// ensemble contenant tous les éléments de la collection c
HashSet<E> e2 = new HashSet<E>(c) ;
// ensemble vide
TreeSet<E> e3 = new TreeSet<E>() ;
// ensemble contenant tous les éléments de la collection c
TreeSet<E> e4 = new TreeSet<E>(c) ;
26
Groupe: CPI2-ISIMM 13
Dr Imed ABBASSI 28/02/2019
Ensembles
• Les deux classes HashSet et TreeSet disposent de la
méthode iterator prévue dans l’interface Collection.
• Elle fournit un itérateur monodirectionnel (Iterator)
permettant de parcourir les différents éléments de la
collection:
HashSet<E> e ; // ou TreeSet<E> e
.....
Iterator<E> it = [Link]() ;
while ([Link]()){
E o = [Link]() ; // Object o = [Link]() ; <-- avant JDK 5.0
// utilisation de o
}
• Remarque: Les ensembles ne disposent pas d’un itérateur
bidirectionnel. Les ensembles sont organisés en fonction
des valeurs de leurs éléments.
27
Ensembles
Ajout d’un élément:
• La seule façon d’ajouter un élément à un ensemble est
d’utiliser la méthode add de l’interface Collection.
• Elle s’assure que l’élément en question n’existe pas déjà:
HashSet<E> s ; E e ; // Hashset s ; Object e ; <-- avant JDK 5.0
.....
boolean existe = [Link] (e) ;
if (existe) [Link] (e + " existe deja") ;
else [Link] (e + " a ete ajoute") ;
• Grâce aux techniques utilisées pour implémenter
l’ensemble, l’efficacité du test d’appartenance est en O(1)
pour le type HashSet et en O(Log N) pour le type TreeSet.
28
Groupe: CPI2-ISIMM 14
Dr Imed ABBASSI 28/02/2019
Ensembles
Suppression d’un élément:
• Nous avons vu que pour les autres collections, la méthode
remove de suppression d’une valeur donnée possède une
efficacité en O(N).
• Un des grands avantages des ensembles est d’effectuer
cette opération avec une efficacité en O(1) (pour HashSet)
ou en O(Log N) (pour TreeSet).
• Ici, la méthode remove renvoie true si l’élément a été
trouvé (et donc supprimé) et false dans le cas contraire :
TreeSet<E> ts ; E o ; // TreeSet ts ; Object o ; <-- avant JDK 5.0
.....
boolean trouve = [Link] (o) ;
if (trouve) [Link] (o + " a ete supprime") ;
else [Link] (o + " n’existe pas ") ;
29
Ensembles
• Par ailleurs, la méthode remove de l’itérateur
monodirectionnel permet de supprimer l’élément courant
(le dernier renvoyé par next) le cas échéant:
TreeSet<E> ts ; // TreeSet ts ; <-- avant JDK 5.0
.....
Iterator<E> it = [Link] ();
[Link] () ; [Link] () ; /* deuxième élément = élément courant */
[Link] () ; /* supprime le deuxième élément */
• La méthode contains permet de tester l’existence d’un
élément donné, avec toujours une efficacité en O(1) ou en
O(Log N).
30
Groupe: CPI2-ISIMM 15
Dr Imed ABBASSI 28/02/2019
Ensembles
Exemple 3:
import [Link].* ;
public class TestSet{
public static void main (String args[]){
int t[] = {2, 5, -6, 2, -8, 9, 5} ;
TreeSet<Integer>hs = new TreeSet<Integer>() ;
for (int v : t) {
boolean ajoute = [Link](v) ;
if (ajoute) [Link] (" On ajoute " + v) ;
else [Link] (" " + v + " est deja present") ;
}
[Link] ("Ensemble en A = ") ; affiche (hs) ;
boolean enleve = [Link] (5) ;
if (enleve) [Link] (" On a supprime 5") ;
[Link] ("Ensemble en B = ") ; affiche (hs) ;
boolean existe = [Link] (5) ;
if (!existe)
[Link] (" On ne trouve pas 5") ;
}
31
Ensembles
public static <E> void affiche (TreeSet<E> ens) {
Iterator<E> iter = [Link] ();
while ([Link]()){[Link] ([Link]() + " ");}
[Link] () ;
}
}
• Dans le cas des HashSet, on doit définir convenablement
les méthodes suivantes:
– boolean equals(Object o): sert à définir l’appartenance d’un
élément à l’ensemble.
– int hashCode(): sert à calculer le code de hachage d’un objet.
• Les classes String, File et les classes enveloppes
définissent une méthode hashCode utilisant la valeur de
référence effective des objets.
32
Groupe: CPI2-ISIMM 16
Dr Imed ABBASSI 28/02/2019
Ensembles
• Les autres classes ne (re-)définissent pas hashCode et
l’on recourt à la méthode hashCode héritée de la classe
Object.
Exemple 4: Voici un exemple d’une classe Point qui redéfinit
les deux méthodes hashCode et equals.
import [Link].* ;
public class Point{
private int x, y ;
Point (int x, int y) { this.x = x ; this.y = y ; }
public int hashCode (){ return x+y ; }
public boolean equals (Object pp){
Point p = (Point) pp ;
return ((this.x == p.x) & (this.y == p.y)) ;
}
public String toString(){return "[" + x + " " + y + "] ";}
}
public class TestHashSet{
public static void main (){
33
Ensembles
Point p1 = new Point (1, 3), p2 = new Point (2, 2) ;
Point p3 = new Point (4, 5), p4 = new Point (1, 8) ;
Point tp[] = {p1, p2, p1, p3, p4, p3} ;
HashSet<Point> ens = new HashSet<Point> () ;
for (Point px : tp){
[Link] ("le point "+px);
boolean ajoute = [Link] (px) ;
if (ajoute) [Link] (" a ete ajoute") ;
else [Link] ("est deja present") ;
[Link] ("ensemble = " ) ; affiche(ens) ;
}
}
public static void affiche (HashSet<Point> ens){
Iterator<Point> iter = [Link] ();
while ([Link]()){[Link] ([Link]() + " ");}
[Link] () ;
}
}
34
Groupe: CPI2-ISIMM 17
Dr Imed ABBASSI 28/02/2019
Queues et deques
• Le JDK 5.0 a introduit une nouvelle interface Queue
(dérivée de Collection), destinée à la gestion des files
d’attente (ou queues).
• Il s’agit de structures dans lesquelles on peut
– introduire un nouvel élément, si la queue n’est pas pleine,
– prélever le premier élément de la queue,
• L’introduction d’un nouvel élément dans la queue se fait
à l’aide d’une nouvelle méthode offer qui présente sur la
méthode add (de l’interface Collection) l’avantage de ne
pas déclencher d’exception quand la queue est pleine;
• Dans ce cas, offer renvoie simplement la valeur false.
35
Queues et deques
• Le prélèvement du premier élément de la queue peut se
faire :
– de façon destructive, à l’aide de la méthode poll: l’élément ainsi
prélevé est supprimé de la queue; la méthode renvoie null si la
queue est vide,
– de façon non destructive à l’aide de la méthode peek.
Classes implémentant l’interface Queue: LinkedList.
PriorityQueue.
• La classe PriorityQueue permet de choisir une relation
d’ordre de priorité. Dans ce cas, les éléments doivent être
comparables.
• Les éléments de la queue sont alors ordonnés par cette
relation d’ordre et le prélèvement d’un élément porte alors
sur le "premier" au sens de cette relation.
36
Groupe: CPI2-ISIMM 18
Dr Imed ABBASSI 28/02/2019
Queues et deques
Deque: queues à double entrée
• Cet interface introduit par Java 6 et qui dérive de Queue.
• Il est destiné à gérer des files d’attente à double entrée.
• On peut réaliser l’une des opérations suivantes à l’une des
extrémités de la queue:
– ajouter un élément,
– examiner un élément,
– supprimer un élément.
• Pour chacune de ces opérations, il existe deux méthodes:
1. Méthode déclenchant une exception quand l’opération échoue
(pile pleine ou vide, selon le cas),
2. Méthode renvoyant une valeur particulière (null pour une méthode
de prélèvement ou d’examen, false pour une méthode d’ajout).
37
Queues et deques
• Le tableau suivant illustre ces méthodes:
ArrrayDeque: une implémentation d’une queue à double
entrée sous forme d’un vecteur dynamique.
• Les méthodes spécifiques à cette implémentation:
– descendingIterator
– removeFirstOccurrence
– removeLastOccurrence
38
Groupe: CPI2-ISIMM 19
Dr Imed ABBASSI 28/02/2019
Tables associatives
Map<K,V>: Interface permettant de créer des tables
associatives dont chaque élément comporte deux parties
nommées clé (K) et valeur (V).
• Ces tables sont principalement destinées à retrouver la
valeur associée à une clé donnée.
Implémentation:
• L’intérêt des tables associatives est de pouvoir y retrouver
rapidement une clé donnée pour en obtenir l’information
associée.
• Deux types de tables associatives:
– Table de hachage : classe HashMap
– Arbre binaire : classe TreeMap
39
Tables associatives
• Dans les deux types, seule la clé sera utilisée pour
ordonnancer les informations.
• Dans le premier cas, on se servira du code de hachage des
objets formant les clés;
• Dans le second cas, on se servira de la relation d’ordre
induite par compareTo ou par un comparateur fixé à la
construction.
• L’accès à un élément d’un HashMap sera en O(1) tandis
que celle à un élément d’un TreeMap sera en O(Log N)).
• En contrepartie de leur accès moins rapide, les TreeMap
seront (comme les TreeSet) ordonnés en permanence
suivant leurs clés.
40
Groupe: CPI2-ISIMM 20
Dr Imed ABBASSI 28/02/2019
Tables associatives
Ajout et Suppression d’information:
• Pour ajouter une clé à une table, on utilise la méthode put à
laquelle on fournit la clé et la valeur associée;
• Par exemple, si String désigne le type concret des clés et
des valeurs:
HashMap <String, String> m = new HashMap <String, String> ();
.....
[Link] ("Java",3) ;
• Si la clé fournie à put existe déjà, la valeur associée
remplacera l’ancienne (une clé donnée ne pouvant figurer
qu’une seule fois dans une table).
• D’ailleurs, put fournit en retour soit l’ancienne valeur si la
clé existait déjà, soit null.
41
Tables associatives
• On peut supprimer un élément d’une table en utilisant la
méthode remove, laquelle fournit en retour l’ancienne
valeur associée si la clé existe ou la valeur null dans le cas
contraire.
Recherche d’information:
• On obtient la valeur associée à une clé donnée à l’aide de
la méthode get, laquelle fournit null si la clé cherchée n’est
pas présente (K représente le type de la clé):
HashMap <String, String> m = new HashMap <String, String> ();
[Link] ("CPI", "10") ; [Link] ("LFGL", "20") ;
[Link] ("MRGL", "30") ;[Link] ("MPGL", "40") ;
// retrouver la valeur associee a la cle "CPI"
String ch = [Link]("CPI") ;
42
Groupe: CPI2-ISIMM 21
Dr Imed ABBASSI 28/02/2019
Tables associatives
• L’efficacité de cette recherche est en O(1) pour HashMap
et en O(Log N) pour TreeMap.
• La méthode containsKey (resp. containsValue) permet de
savoir si une clé (valeur) donnée est présente, avec la
même efficacité.
Parcours d’une table:
• En théorie, les types HashMap et TreeMap ne disposent
pas d’itérateurs.
• La méthode entrySet permet de construire, à partir d'une
table, un ensemble d'éléments de paires (type [Link]).
• Les méthodes getKey et getValue du type [Link]<K,V>
permettent d’extraire respectivement la clé et la valeur
d’une paire.
43
Tables associatives
Illustration: K désigne le type concret des clés et V celui des
valeurs.
TreeMap <K,V> tmap;
tmap = new V () ;
.....
Set <[Link] <K,V> entrees = [Link] () ;
for ([Link]<K,V> courant: entrees) {
K cleCourante = [Link] () ;
V valCourante = [Link] () ;
[Link] (cleCourante + " : ") ;
…
}
• L’ensemble fourni par entrySet n’est pas une copie des
informations figurant dans la table m. Il s’agit d’une "vue".
• Si on opère des modifications dans m, elles seront
directement perceptibles sur la vue associée.
44
Groupe: CPI2-ISIMM 22
Dr Imed ABBASSI 28/02/2019
Chapitre 2: Threads
1. Introduction
2. Création de threads
3. Interface Runnable
4. Priorités des threads
5. Interruption d’un thread
6. Threads démons et arrêt brutal
7. Coordination de threads
8. Cycle de vie d’un thread
45
Introduction
• Un programme peut exécuter plusieurs tâches en parallèles.
• Il comporte toujours au moins un thread dit « thread
principal » correspondant à la méthode main.
• Chaque tâche du programme est effectuée par un
processus léger appelé Thread.
Avantages:
– légèreté grâce au partage des données
– meilleures performances au lancement et en exécution
– partage les ressources système (pratique pour les I/O).
Utilité:
– puissance de la modélisation : un monde multithread
– puissance d'exécution : parallélisme
– simplicité d'utilisation: c'est un objet Java.
46
Groupe: CPI2-ISIMM 23
Dr Imed ABBASSI 28/02/2019
Création de threads
• En Java, un thread est un objet d’une classe ordinaire qui
dispose d’une méthode qui s’appelle run qui sera exécutée
lorsque le thread sera démarré;
• Cette classe peut être définie de deux façons:
– Solution 1: créer une classe dérivée de la classe Thread;
– Solution 2: créer une classe qui implémente l'interface
Runnable.
• La première solution est la plus simple, mais elle présente
un inconvénient: la classe ne peut pas étendre une autre
classe au choix;
• Dans certains cas, on a besoin créer une classe de threads
qui hérite d’une autre classe.
47
Création de threads
Classe Thread:
• Cette classe appartenant au paquetage [Link], permet
de créer des objets threads.
• Un thread peut appartenir un groupe (hiérarchie) de
threads. Chaque groupe est un objet de la classe
ThreadGroup.
Constructeurs principaux de Thread:
– public Thread()
– public Thread(Runnable target, String name)
– public Thread(Runnable target, String name)
– public Thread(ThreadGroup group, Runnable target, String
name) Throws SecurityException
48
Groupe: CPI2-ISIMM 24
Dr Imed ABBASSI 28/02/2019
Création de threads
Quelques méthodes de Thread:
– void setPriority: fixe le niveau de priorité d'un thread .
– void run(): cette méthode définit le traitement demandé du thread.
– void start(): fais exécuter la méthode run d’un thread.
– static Thread currentThread(): retourne une instance de la classe
Thread qui est le thread en cours d'exécution.
– static void sleep permet de suspendre l'exécution du thread en
cours pendant une période spécifiée.
– final void stop(): arrête l'exécution du thread en cours d'exécution.
– final void join(): permet à un thread d’attendre la fin d’un autre.
– public static void yield(): permet de passer la main à un autre
thread de priorité égale ou supérieure.
• Ces méthodes peuvent déclencher des exceptions comme
InterruptedException et IllegalThreadStateException, etc.
49
Création de threads
Exemple 1: Un thread simple affichant un certain nombre de
fois un texte donné.
class Ecrit extends Thread {
private String texte ;
private int nb ;
private long attente;
public Ecrit (String texte, int nb, long attente) {
[Link] = texte ; [Link] = nb ;
[Link] = attente ;
}
public void run () {
try{ for (int i=0 ; i<nb ; i++) {
[Link] (texte) ; sleep (attente) ;
}
} catch (InterruptedException e) {} // impose par sleep
}
}
50
Groupe: CPI2-ISIMM 25
Dr Imed ABBASSI 28/02/2019
Création de threads
• Voici un programme d’utilisation de la classe Ecrit:
public class MainThread {
public static void main (String args[]) {
Ecrit e1 = new Ecrit ("bonjour ", 10, 5) ;
Ecrit e2 = new Ecrit ("bonsoir ", 12, 10) ;
Ecrit e3 = new Ecrit ("\n", 5, 15) ;
[Link]() ;
[Link]() ;
[Link]() ;
}
}
• Ce programme comporte quatre threads dont l’un
correspond la méthode main et les autres sont des
instances de la classe Ecrit.
51
Interface Runnable
• L'autre façon de créer un thread consiste à déclarer une
classe qui implémente l'interface Runnable.
• Application à l’exemple précédent:
class Ecrit implements Runnable{
public Ecrit (String texte, int nb, long attente) {
// mêmes instructions que précédemment
}
public void run () {// même contenu que précédemment }
}
• Nous serons amenés à créer des objets de type Ecrit, par
ex: Ecrit e1 = new Ecrit("bonjour", 10,5);
• Cette fois, ces objets ne sont plus des threads et ne
peuvent donc plus être lancés par start.
52
Groupe: CPI2-ISIMM 26
Dr Imed ABBASSI 28/02/2019
Interface Runnable
• Pour lancer l'exécution d’une instance Runnable e1, on doit
procéder comme suit:
– Etape 1: Créer un thread contrôleur t1 (objet de Thread) en
utilisant une forme particulière de constructeur recevant en argument
un objet implémentant l’interface Runnable:
Thread t1=new Thread(e1);
– Etape 2: Lancer classiquement le thread t1 par start:
[Link]();
Contrôleur du thread:
• Une instance de Thread (ou une classe fille) intermédiaire entre
le thread et les objets de l’application.
• Un contrôleur a des informations sur l’état du thread (son nom, sa
priorité, s’il est en vie ou non,…).
53
Interface Runnable
Exemple complet:
class Ecrit implements Runnable{
private String texte ;
private int nb ; public class MainThread {
private long attente; public static void main (String args[]){
public Ecrit (String texte, int nb, long attente){ Ecrit e1 = new Ecrit ("bonjour ", 10, 5) ;
[Link] = texte ; Ecrit e2 = new Ecrit ("bonsoir ", 12, 10) ;
[Link] = nb ; Ecrit e3 = new Ecrit ("\n", 5, 15) ;
[Link] = attente ; Thread t1 = new Thread (e1) ;
} [Link]() ;
Thread t2 = new Thread (e2) ;
public void run (){
[Link]() ;
try{ for (int i=0 ; i<nb ; i++){
Thread t3 = new Thread (e3) ;
[Link] (texte) ; [Link]() ;
[Link] (attente) ; }
} }
}catch (InterruptedException e) {}
}
}
54
Groupe: CPI2-ISIMM 27
Dr Imed ABBASSI 28/02/2019
Priorités des threads
• Les threads possédaient tous la même priorité par défaut
NORM_PRIORITY=5.
• Il est possible de modifier la priorité d’un thread à l’aide de
la méthode setPriority à laquelle on fournit en argument
une valeur entière comprise entre [Link] (en fait 1)
et [Link] (en fait 10).
Règles de priorité de threads:
• R1: Le thread de plus haute priorité est choisie parmi ceux
qui sont dans l’état prêt; S’il y a plusieurs threads candidats,
le thread choisi dépendra de l’environnement ;
• R2: Si un thread t1 plus prioritaire que le thread en cours
d’exécution t2, il prend la main et t2 passe à l’état prêt.
55
Interruption d’un thread
Utilité d’interruption:
• Dans l’exemple précédent, les threads s’achevaient tout
naturellement avec la fin de l’exécution de leur méthode run.
• Dans certains cas, on peut avoir besoin d’interrompre
prématurément un thread depuis un autre thread.
• Ce besoin peut devenir fondamental dans le cas de ce que
nous nommerons des « threads infinis », c’est-à-dire dans
lesquels la méthode run n’a pas de fin programmée;
• Ceci pourrait être le cas d’un thread de surveillance
d’appels dans un serveur Web.
56
Groupe: CPI2-ISIMM 28
Dr Imed ABBASSI 28/02/2019
Interruption d’un thread
Démarche usuelle: utilisation de la méthode interrupt de la
classe Thread.
• La méthode interrupt permet à un thread t1 d’interrompre un
autre t2;
[Link](); //positionne un indicateur dans t2
• Cette méthode demande à l’environnement de positionner un
indicateur signalant une demande d’arrêt du thread t.
• Deux façons pour déterminer l'état d'interruption d'un thread:
– static boolean interrupted(): Teste si le thread en cours a été
interrompue. Cette méthode remet à false l’indicateur de demande
d’interruption.
– boolean isInterrupted(): Teste si un thread a été interrompu. L'état
d'interruption du thread n'est pas affecté par cette méthode.
57
Interruption d’un thread
Exemple 2: Un thread affichant indéfiniment un texte;
public class MainThread { class Ecrit extends Thread {
public static void main (String args[]) { private String texte ;
Ecrit e1 = new Ecrit ("bonjour ", 5) ; private long attente ;
Ecrit e2 = new Ecrit ("bonsoir ", 10) ; public Ecrit (String texte, long attente)
Ecrit e3 = new Ecrit ("\n", 35) ; {
[Link]() ; [Link] = texte ;
[Link]() ; [Link] = attente ;
[Link]() ; }
[Link](); public void run () {
[Link]() ; // interruption premier thread try {
[Link] ("\n*** Arret premier thread ***") ;
while (true){ // boucle infinie
[Link]();
if (isInterrupted()) return;
[Link]() ; // interruption deuxième thread
[Link]() ; // interruption troisième thread [Link] (texte) ;
[Link] ("\n*** Arret deux derniers threads ***") ; sleep (attente) ;
} }
} } catch (InterruptedException e) {}
}
}
58
Groupe: CPI2-ISIMM 29
Dr Imed ABBASSI 28/02/2019
Interruption d’un thread
Remarques:
• Si une exception n’est pas traitée (par un bloc try-catch), elle interrompt
l’exécution du thread courant mais pas des autres threads
• La méthode run ne peut pas lancer une exception contrôlée car elle
redéfinit une méthode sans clause « throws ».
• On peut rassembler plusieurs threads dans un groupe, c’est-à-dire un
objet de type ThreadGroup qu’on fournit en argument du constructeur
des threads.
• Dans ce cas, il est alors possible d’envoyer une demande d’interruption
par interrupt au groupe, ce qui équivaut à l’envoyer à chacun des
threads du groupe.
ThreadGroup group = new ThreadGroup("GroupEcrit");
Thread t1 = new Thread(group,"Thread-1");
Thread t2 = new Thread(group,"Thread-2");
59
Threads démons et arrêt brutal
Principe:
• Un programme est amené à lancer un ou plusieurs threads.
• Jusqu’ici, nous avons considéré qu’un programme se
terminait lorsque le dernier thread le constituant était arrêté.
• En réalité, il existe deux catégories de threads :
– Utilisateurs: des threads créés par l’utilisateurs.
– Démons: des threads effectuant des tâches non
prioritaires et souvent créés par la JVM.
• Par défaut, un thread est créé dans la catégorie utilisateur.
• Un thread démon peut s’arrêter brutalement à n’importe
quel moment de sa méthode run().
60
Groupe: CPI2-ISIMM 30
Dr Imed ABBASSI 28/02/2019
Threads démons et arrêt brutal
Propriété (thread démon): Si à un moment donné, les seuls
threads en cours d’exécution d’un même programme sont des
démons, ces derniers sont arrêtés brutalement et le
programme se termine.
• Pour faire d’un thread t un démon, on effectue l’appel
« [Link](true); » avant d’appeler la méthode start.
• L’exécution de la méthode setDaemon peut déclencher une
exception IllegalThreadStateException.
• La méthode [Link] met fin à un programme et
provoque, elle-aussi, l’arrêt brutal de tous les threads
utilisateurs/démons en cours d’exécution.
61
Threads démons et arrêt brutal
Exemple 3: adaptation de l’exemple précédent:
public class Demons{
public static void main (String args[]){
Ecrit e1 = new Ecrit ("bonjour ", 5) ;
Ecrit e2 = new Ecrit ("bonsoir ", 10) ;
Ecrit e3 = new Ecrit ("\n", 35) ;
[Link] (true) ; [Link]() ;
[Link] (true) ; [Link]() ;
[Link] (true) ; [Link]() ;
[Link]() ; // met fin au main, donc ici aux trois autres threads démons
}
}
• Le thread principal (main) s’arrête après la saisie au clavier
d'un texte quelconque.
• On constate que les trois threads sont interrompus.
62
Groupe: CPI2-ISIMM 31
Dr Imed ABBASSI 28/02/2019
Coordination de Threads
• L’avantage des threads sur les processus, c’est qu’ils
appartiennent à un même programme.
• Les threads peuvent donc éventuellement partager les
mêmes objets.
• Cet avantage s’accompagne parfois de contraintes.
Règles de partage de données:
– R1: Il faut éviter que deux threads puissent accéder en même temps
à un objet.
– R2: Un thread doit attendre un autre d’avoir fini un travail sur un
objet avant qu’il y accède à son tour.
• La première (resp. deuxième) contrainte sera réglée par les
« méthodes synchronisées » (resp. des mécanismes
d’attente et notification).
63
Coordination de Threads
Méthodes synchronisées: utilisées pour synchroniser l’exécution
de différents threads afin de conserver une cohérence sur les
données qu'ils partagent.
• Syntaxe de déclaration:
synchronized return_type function_name(parms)
{
…..
}
• A un instant donné, une seule méthode synchronisée peut être
appelée pour un objet donné.
• Une méthode synchronisée peut être aussi statique. Deux
méthodes statiques d'une même classe ne peuvent être
invoquées simultanément.
64
Groupe: CPI2-ISIMM 32
Dr Imed ABBASSI 28/02/2019
Coordination de Threads
Exemple 4: Calcul et l’affichage du carré d’un nombre entier n.
• Considérons un programme constitué de 2 threads répétant
indéfiniment les actions suivantes:
– Premier thread: Incrémentation d’un nombre n et calcul de
son carré.
– Second thread: Affichage du nombre n et de son carré.
• Il s’agit de partager n et son carré entre deux threads. Ces deux
données sont regroupées dans un objet nomb de type Nombres.
• On voit que si le premier thread se trouve interrompu entre
l’incrémentation et le calcul de carré du n, alors que le second
risque d’afficher le nouveau nombre et l’ancien carré.
65
Coordination de Threads
• La classe Nombres dispose de deux méthodes synchronisées
(mutuellement exclusives):
– calcul qui incrémente n et calcule la valeur de carre
– affiche qui affiche les valeurs de n et de carre
public class Nombres {
private int n=0, carre ;
public synchronized void calcul() {n++ ; carre = n*n ; }
public synchronized void affiche (){
[Link] (n + " a pour carre " + carre) ;
}
}
• Nous créons 2 threads dont l’un est chargé pour le calcul et
l’autre pour l’affichage.
66
Groupe: CPI2-ISIMM 33
Dr Imed ABBASSI 28/02/2019
Coordination de Threads
• Les deux threads sont lancés par main et interrompus lorsque
l’utilisateur le souhaite.
public class Main {
public static void main (String args[]) {
Nombres nomb = new Nombres() ;
Thread calc = new ThreadCalcul (nomb) ;
Thread aff = new ThreadAffichage (nomb) ;
[Link] ("Suite de carres - tapez retour pour arreter") ;
[Link]() ;
[Link]() ;
[Link]() ;
[Link]() ;
[Link]() ;
}
}
67
Coordination de Threads
• Définition des classes ThreadCalcul et ThreadAffichage:
public class ThreadCalcul extends Thread {
public ThreadCalcul (Nombres nomb) { [Link] = nomb ;}
public void run () {
try { while (!interrupted()) { [Link] () ;sleep (50) ;} }
catch (InterruptedException e) {}
}
private Nombres nomb ;
}
public class ThreadAffichage extends Thread{
public ThreadAffichage(Nombres nomb){[Link]=nomb;}
public void run () {
try{ while (!interrupted()){ [Link]();sleep (75) ;}}
catch (InterruptedException e) {}
}
private Nombres nomb ;
}
68
Groupe: CPI2-ISIMM 34
Dr Imed ABBASSI 28/02/2019
Coordination de Threads
Notion de verrou:
• Ce mécanisme d’exclusion mutuelle est basé sur l’objet lui-même
et non sur le thread.
• Cette distinction peut s’avérer importante dans une situation
comme celle-ci.
synchronized void f (...) // on suppose f appelée sur un objet o
{ ..... // partie I
g () ; // appel de g sur le même objet o
..... // partie II
}
void g(...) // g n’est pas synchronisée
{ .....}
• La méthode f appelle g sur le même objet o. Le verrou de l’objet
o, attribué initialement à f, est rendu lors de l’appel de g.
69
Coordination de Threads
• Dans le cas où g est non synchronisée, alors elle peut être
interrompue par un autre thread qui peut modifier l’objet o.
• On ne garantit que o ne soit pas modifié entre l’exécution de
partie I et celle de partie II que si g était aussi synchronisée.
L’instruction synchronized:
synchronized (objet){ suite d’instructions; }
• Une méthode synchronisée acquiert donc le verrou sur l’objet qui
l’a appelée pour toute la durée de son exécution.
• L’utilisation d’une méthode synchronisée comporte deux
contraintes :
– l’objet concerné est nécessairement celui qui l’a appelée.
– l’objet est verrouillé pour toute la durée de l’exécution de la méthode.
70
Groupe: CPI2-ISIMM 35
Dr Imed ABBASSI 28/02/2019
Coordination de Threads
• L’instruction synchronized permet, à un thread, d’acquérir un
verrou sur un objet quelconque pour une durée limitée à
l’exécution d’un bloc d’instructions.
• L'objet en entrée de l'instruction synchronized est appelé
moniteur.
Interblocage:
• L’utilisation de verrous sur des objets peut conduire à une
situation de blocage, connue sous le nom d’ "étreinte mortelle"
qui peut se définir ainsi:
– Le thread t1 possède le verrou de l’objet o1 et il attend le verrou de l’objet o2
– Le thread t2 possède le verrou de l’objet o2 et il attend le verrou de l’objet o1
Java n’est pas en mesure de détecter ce genre de situation et
c’est au programmeur qu’il incombe de gérer cette tâche.
71
Coordination de Threads
Attente et notification: wait(), notify() et notifyAll()
• Il arrive des situations où l’on doit coordonner l’exécution des
threads: attente d’un thread, notification d’un ou plusieurs
threads.
• Java offre un mécanisme basé sur l’objet et sur les méthodes
synchronisées que nous venons d’étudier :
– Une méthode synchronisée peut appeler la méthode wait de
l’objet dont elle possède le verrou, ce qui a pour effet :
• de rendre le verrou à l’environnement qui pourra, l’attribuer à une
autre méthode synchronisée
• de mettre en attente le thread correspondant; plusieurs threads
peuvent être en attente sur un objet;
– Une méthode synchronisée peut appeler la méthode notify (resp.
notifyAll) d’un objet pour prévenir un (resp. tous les threads) thread en
attente sur cet objet.
72
Groupe: CPI2-ISIMM 36
Dr Imed ABBASSI 28/02/2019
Coordination de Threads
Méthode wait(): Une méthode finale de la classe Thread
permettant d'interrompre l’exécution d'un thread.
• Cette méthode peut déclencher une exception de type
InterruptedException lorsque le thread est déjà interrompu.
• Syntaxe et règles d’utilisation:
synchronized void f (...) // on suppose f appelée sur un objet o
{ .....
wait();
}
– nécessite que le thread en cours possède le moniteur de objet o.
– bloque le thread qui l’appelle, jusqu’à ce qu’un autre thread
appelle la méthode [Link]() ou [Link]().
– libère le moniteur de l’objet (l’opération « blocage du thread –
libération du moniteur » est atomique)
73
Coordination de Threads
Méthode notifyAll: Une méthode finale de la classe Thread
permettant à un thread en cours d’envoyer une notification à tous
les autres threads et leur donner la possibilité de s’exécuter.
• Syntaxe et règles d’utilisation:
synchronized void f (...) // on suppose f appelée sur un objet o
{ .....
notifyAll();
}
– nécessite que le thread en cours possède le moniteur de l’objet.
– débloque tous les threads qui s’étaient bloqués sur l’objet avec
[Link]().
74
Groupe: CPI2-ISIMM 37
Dr Imed ABBASSI 28/02/2019
Coordination de Threads
Méthode notifyAll: Une méthode finale de la classe Thread
permettant de débloquer tous les threads qui s’étaient bloqués
sur l’objet avec [Link]().
• Syntaxe et règles d’utilisation:
synchronized void f (...) // on suppose f appelée sur un objet o
{ .....
notifyAll();
}
– nécessite que le thread en cours possède le moniteur de l’objet.
– Un seul des threads débloqués va récupérer le moniteur ; on ne
peut prévoir lequel.
– Les autres devront attendre qu’il relâche le moniteur pour être
débloqués à tour de rôle, mais ils ne sont plus bloqués par un
wait.
75
Coordination de Threads
Méthode notify: Une méthode finale de la classe Thread
permettant de débloquer un seul thread qui s’était bloqué sur
l’objet avec [Link]().
• Syntaxe et règles d’utilisation:
synchronized void f (...) // on suppose f appelée sur un objet o
{ .....
notify();
}
– nécessite que le thread en cours possède le moniteur de l’objet.
– Requière qu’un seul thread soit bloqué sur l’objet avec wait().
– L’objet débloqué va récupérer le moniteur ;
Remarque: il est recommandé d’utiliser notifyAll() dans une
méthode synchronisée pour la notification de threads.
76
Groupe: CPI2-ISIMM 38
Dr Imed ABBASSI 28/02/2019
Coordination de Threads: Gestion d’une réserve
• Considérons une application de gestion d’une « réserve ».
• L’application comporte trois threads:
– Un thread qui ajoute une quantité donnée.
– Deux threads qui puisent chacun une quantité donnée.
• Un thread ne peut puiser dans la réserve que si elle contient
une quantité suffisante.
• La réserve est représentée par un objet de type Reserve qui
dispose de deux méthodes synchronisées puise et ajoute:
– Lorsque puise s’aperçoit que la réserve est insuffisante, elle appelle
wait pour mettre le thread correspondant en attente
– Parallèlement, ajoute appelle notifyAll après chaque ajout.
• Les 3 threads sont lancés par main et interrompus lorsque
l’utilisateur le souhaite (en frappant un texte)
77
Coordination de Threads: Gestion d’une réserve
public class Reserve {
private int stock = 500 ; // stock initial = 500
public synchronized void puise (int v) throws
InterruptedException {
if (v <= stock) { [Link] ("-- on puise " + v) ;
stock -= v ;
[Link] (" et il reste " + stock ) ;
}
else {
[Link] ("** stock de " + stock + " insuffisant pour puiser " + v ) ;
wait() ;
}
}
public synchronized void ajoute (int v) {
stock += v ;
[Link] ("++ on ajoute " + v + " et il y a maintenant " + stock) ;
notifyAll() ;
}
}
78
Groupe: CPI2-ISIMM 39
Dr Imed ABBASSI 28/02/2019
Coordination de Threads: Gestion d’une réserve
public class ThreadAjout extends Thread {
private int vol, delai;
private Reserve r;
public ThreadAjout (Reserve r, int vol, int delai) { [Link] = vol ; this.r = r ; [Link] = delai ;}
public void run () {
try { while (!interrupted()) {[Link] (vol) ;sleep (delai) ;}
} catch (InterruptedException e) {}
}
}
public class ThreadPuise extends Thread {
private Reserve r ;
private int delai, vol ;
public ThreadPuise(Reserve r, int delai, int vol) {this.r = r;[Link] = delai; [Link] = vol; }
public void run () {
try { while (!interrupted()) { [Link] (vol) ; sleep (delai) ;}
} catch (InterruptedException e) {}
}
}
79
Coordination de Threads: Gestion d’une réserve
public class Synchro3 {
public static void main (String args[]) {
Reserve r = new Reserve () ;
ThreadAjout ta1 = new ThreadAjout (r, 100, 15) ;
ThreadAjout ta2 = new ThreadAjout (r, 50, 20) ;
ThreadPuise tp = new ThreadPuise (r, 300, 10) ;
[Link] ("Suivi de stock --- faire entree pour arreter ") ;
[Link] () ;
[Link] () ;
[Link] () ;
[Link]();
[Link] () ;
[Link] () ;
[Link] () ;
}
}
80
Groupe: CPI2-ISIMM 40
Dr Imed ABBASSI 28/02/2019
Coordination de Threads: retour sur exemple 4
• Les deux threads calc et aff n’étaient pas coordonnés.
• On pouvait incrémenter plusieurs fois le nombre avant qu’il
n’y ait d’affichage ou encore afficher plusieurs fois les
mêmes informations.
• On va faire en sorte que malgré leurs rythmes différents, les
deux threads soient coordonnés, c.à.d. qu’on effectue
alternativement une incrémentation et un calcul.
• Pour ce faire, on utilise wait et notifyAll ainsi qu’un
indicateur booléen prêt permettant aux deux threads de
communiquer entre eux.
81
Coordination de Threads: retour sur exemple 4
public class Nombres {
private int n=1, carre ;
private boolean pret = false ;
public synchronized void calcul() throws InterruptedException {
if (!pret) { n++ ;
carre = n*n ; pret = true ;
notifyAll() ;
} else wait() ;
}
public boolean pret () { return pret ; }
public synchronized void affiche () throws InterruptedException{
if (pret){
[Link] (n + " a pour carre " + carre) ; pret=false;
notifyAll() ;
}
wait();
}
}
82
Groupe: CPI2-ISIMM 41
Dr Imed ABBASSI 28/02/2019
Coordination de Threads: retour sur exemple 4
public class ThreadAffichage extends Thread{
……
}
public class ThreadCalcul extends Thread {
…..
}
public class Main {
public static void main(String[] args) {
Nombres nomb = new Nombres();
Thread calc = new ThreadCalcul(nomb);
Thread aff = new ThreadAffichage(nomb);
[Link](); [Link]();
[Link]("Suite de carres - tapez retour pour arreter");
[Link]();
[Link](); [Link]();
}
}
83
Cycle de vie d’un thread
Principe:
• Nous avons vu comment un
thread peut se mettre en « attente
» ou en « sommeil »;
• On va faire ici le point sur les
différents états dans lesquels
peut se trouver un thread et sur
les actions qui les font passer
d’un état à un autre.
Les différents états d’un thread
84
Groupe: CPI2-ISIMM 42
Dr Imed ABBASSI 28/02/2019
Cycle de vie d’un thread
Les états d’un thread:
• Au départ, on crée un objet thread.
• Tant que l’on ne fait rien, il n’a
aucune chance d’être exécuté.
• L’appel de start rend le thread
disponible pour l’exécution (il est
considéré comme prêt).
• L’environnement peut faire passer le
thread de l’état prêt à l’état en cours
d’exécution (c’est le système qui
décide).
• Un thread en cours d’exécution peut
subir différentes actions:
– interrompu et revenir à l’état
prêt. Les différents états d’un thread
– Mis en sommeil par appel de
sleep…
85
Chapitre 3: Classes internes & Anonymes
1. Introduction
2. Classes membres
3. Classes locales
4. Classes anonymes
5. Interfaces membres
6. Expressions lambda
7. Résolution de liens
86
Groupe: CPI2-ISIMM 43
Dr Imed ABBASSI 28/02/2019
Introduction
• Classe interne: une classe définie à l’intérieur d’une
autre afin de définir des types hiérarchiques et des types
concrets implantant des interfaces et des classes
abstraites.
• Catégories de classes internes:
– Les classes membres
– Les interfaces membres d’une classe
– Les classes membres statiques d’une
classe/interface
– Classes locales d’une méthode
– Classes anonymes
87
Classes membres
• Une classe membre est une classe java définie dans la
partie déclaration des membres d'une autre classe
(nommée classe englobante).
• Deux catégories de classes membres:
– Classes membres non statiques: comportent uniquement des
méthodes non statiques et associées à une instance de la classe
englobante.
– Classes membres statiques.
Syntaxe:
public class englobante {
< membres de genre attributs >
< membres de genre méthodes >
< membres de genre classes >
}
88
Groupe: CPI2-ISIMM 44
Dr Imed ABBASSI 28/02/2019
Classes membres
• Règles d'accessibilité: les mêmes que celles des
attributs.
• L'accès à une classe membre (Inner) d'une autre
(Outer) se fait comme suit :
– Depuis l'intérieur: [this.]Inner
– Depuis une classe dérivée: [Link]
– Depuis l'extérieur: [Link]
• Création d’objets d’une classe membre statique:
[Link] in = new [Link] (params);
• Création d’objets d’une classe membre non statique:
Outer out = new Outer(params);
[Link] in = [Link] Inner (params);
89
Classes membres
Exemple 1:
class G {
static class A {
public void show(){[Link]("A");}
}
class B {public void show(){[Link]("B");}}
}
public class Main {
public static void main(String[] args) {
G g = new G();
G.A a = new G.A();
G.B b = [Link] B();
[Link](); [Link]();
}
}
90
Groupe: CPI2-ISIMM 45
Dr Imed ABBASSI 28/02/2019
Classes membres
• L'accès aux attributs/méthodes de la classe
englobante à partir de la classe membre non
statique se fait comme suit: [Link]
Exemple 2:
class Outer {
private int x;
class A{
boolean t;
public void init(boolean t, int x){
this.t=t; //ok This est une variable non
[Link].x=x; //ok statique. Donc, elle ne
}} peut pas être référencée
static class B{
public B(int x){ dans un contexte
[Link].x=x; // erreur! statique.
}
}}
91
Classes membres
• Considérons les classes suivantes.
package p2; package p1;
class G4 extends G1{. . . } class G1{
class G5 {. . . } public static class A{ … }
protected class B{ … }
package p1; static class C{ … }
class G2 extends G1{. . . } private class D{ … }
class G3 {. . . } ...
}
• Complétez la table suivante:
Accessibilité G1 G2 G3 G4 G5
A OUI OUI OUI OUI OUI
B OUI
C OUI
D OUI
92
Groupe: CPI2-ISIMM 46
Dr Imed ABBASSI 28/02/2019
Classes membres
• JAVA autorise la définition des classes membres
d'une interface.
• Ces classes membres sont implicitement
statiques et publiques.
Exemple 3:
interface IOuter{
class A{A(){[Link]("A");}}
class B{B(){[Link]("B");}}
void outer();
}
class Outer implements IOuter{
@Override
public void outer(){ A a = new A();B b = new B();}
}
93
Classes locales
• Une classe locale se déclare dans un bloc d'une méthode
d'une classe qui la contient (nommée classe englobante).
• Restrictions:
– Une classe locale ne peut pas être qualifiée de publique,
privée, protégée ou statique.
– Une classe locale peut accéder aux :
• variables locales constantes (ou effectivement constantes) de
la méthode.
• attributs de la classe englobante.
– La portée d’une classe locale est le bloc dans lequel elle est
définie.
– Lorsque la classe est locale à une méthode statique, elle ne
peut accéder qu'aux attributs statiques de la classe
englobante.
94
Groupe: CPI2-ISIMM 47
Dr Imed ABBASSI 28/02/2019
Classes locales
Exemple 4:
class Outer {
void outerMethod() {
[Link]("inside outerMethod");
class Inner {
void innerMethod() {
[Link]("inside innerMethod");
}
}
Inner y = new Inner();
[Link]();
}
}
public class Main {
public static void main(String[] args) {
Outer x = new Outer();
[Link]();
}
}
95
Classes locales
Exemple 5:
class Outer {
public int x0 = 5 ;
private int x1=8;
public void outerMethod(int x0, int x1) {
[Link].x1=x1;
class Local1 {
public int j = x1; // c'est la variable x1 local à outerMethod()
int c = [Link].x0; // c'est la variable x0 de OuterClass
}
[Link].x0=(new Local1().c);
for (int i = 0; i<10; i++) {
int k = i;
class Local2 {
int j = k + x1 + x0; // c'est la variable k local au bloc for
}
[Link].x0=(new Local2().j);
}
[Link]("x0="+[Link].x0+", x1="+[Link].x1);
}}
96
Groupe: CPI2-ISIMM 48
Dr Imed ABBASSI 28/02/2019
Classes anonymes
• Une classe anonyme est une classe locale qui ne
porte pas de nom.
• Caractéristiques:
– Une classe anonyme possède toutes les propriétés d'une
classe locale.
– Une classe anonyme permet de définir des types concrets
implantant des interfaces et des classes abstraites.
• Une classe anonyme est instanciée immédiatement
dans sa déclaration comme suit:
new <nom de classe ou d’interface > ([<paramètres>]) {
/* Définition des attributs et méthodes de la classe
anonyme */
}
97
Classes anonymes
Exemple 6: implémentation d’interface
interface Account {
public String getAccountType();
}
public class Main {
public static void main(String[] args) {
Account ram= new Account() {
public String getAccountType(){
return "Saving Account";
}
};
Account hcl= new Account() {
public String getAccountType(){
return "Current Account";
}
};
[Link]([Link]()); // Saving Account
[Link]([Link]()); // Current Account
}
}
98
Groupe: CPI2-ISIMM 49
Dr Imed ABBASSI 28/02/2019
Classes anonymes
Exemple 7: implémentation d’une classe abstraite
abstract class Account {
float solde =0;
public Account(float solde){[Link]=solde;}
abstract String getAccountType();
}
public class Main {
public static void main(String[] args) {
Account ram= new Account(20) {
public String getAccountType(){
return "Saving Account";
}};
Account hcl= new Account(30) {
public String getAccountType(){
return "Current Account";
}};
[Link]([Link]()); // Saving Account
[Link]([Link]()); // Current Account
}}
99
Interfaces membres
• JAVA autorise la définition d'une interface en
tant que membre d'une autre classe (ou
interface).
• Les interfaces membres disposent des mêmes
règles d'accessibilité des classes membres
statiques.
Exemple 7:
class Account{
public interface IAccount{
String getAccountType();
void crédider(float somme);
boolean débiter(float somme);
}
...
}
100
Groupe: CPI2-ISIMM 50
Dr Imed ABBASSI 28/02/2019
Interfaces membres
• Une interface membre peut être implémentée de plusieurs
façons:
– Méthode 1: utilisation d'une classe concrète
– Méthode 2: utilisation d'une classe anonyme
– Méthode 3: utilisation de l'expression lambda
Implémentation: se fait selon les règles de visibilité.
• Private: l’implémentée se fait dans la classe englobante.
• Protected: l’implémentée peut se faire de trois façons:
– Dans la classe englobante.
– Dans le paquetage de la classe englobante.
– Dans une classe dérivée de la classe englobante.
• Public/default: l’interface membre peut être implémentée à
l’extérieur/intérieur du paquetage de sa classe englobante.
101
Interfaces membres
Exemple 8: l’implémentation de l’interface membre
IAccount en dehors de la classe Account.
class SavingAccount implements [Link]{
private float solde;
public SavingAccount(float solde){[Link]=solde;}
@Override
public String getAccountType(){return "Saving Account";}
@Override
public void crédider(float somme){solde+=somme;}
@Override
public boolean débiter(float somme){
if (solde >=somme) {
solde-=somme;
return true;
}
else return false;
}
public float getSolde(){return solde;}
}
102
Groupe: CPI2-ISIMM 51
Dr Imed ABBASSI 28/02/2019
Interfaces membres
Exemple 9: l’implémentation de l’interface membre
IAccount par une classe membre de Account.
class Account{
public interface IAccount{ . . . }
class CurrentAccount implements IAccount{
private float solde;
public CurrentAccount(float solde){[Link]=solde;}
public String getAccountType(){return "Current Account";}
public void crédider(float somme){solde+=somme;}
public boolean débiter(float somme){
if (solde >=somme) {
solde-=somme;
return true;
}
else return false;
}
public float getSolde(){return solde;}
}
}
103
Expressions lambda
Origine: Introduites depuis Java 8 pour implémenter
principalement des interfaces fonctionnelles.
• Similaires aux fonctions car elles acceptent des
paramètres.
Syntaxe:
([liste d’arguments]) -> {corps de l’expression lambda}
ou s’il n’y a qu’un seul traitement :
([liste d’arguments]) ->expression
• Le corps de l’expression peut comporter zéro ou
plusieurs instructions;
• Une expression lambda peut être fournit comme un
paramètre à une méthode.
104
Groupe: CPI2-ISIMM 52
Dr Imed ABBASSI 28/02/2019
Expressions lambda
Exemple 10:
public class Main{
public static void main(String args[]) {
Vector<Integer> v = new Vector();
[Link](1);
[Link](2);
[Link](3);
[Link](4);
[Link]((n)->[Link](n+" "));
[Link]();
[Link]( (n)->{if (n%2 == 0)
[Link](n+" ");
}
);
}
}
105
Expressions lambda
Exemple 11:
class Square{
interface SquareRoot {
double findSquareRoot(int n);
}
}
public class Main{
public static void main(String args[]) {
[Link] squareRoot = (int n) ->{
return ([Link](n));
};
int a=81;
double s=[Link](a);
[Link]("sqrt("+a+")="+s);
}
}
106
Groupe: CPI2-ISIMM 53
Dr Imed ABBASSI 28/02/2019
Résolution de liens
• L’association entre l’appel et la définition de
méthode s’appelle liaison (ou Binding).
• Deux types liaisons:
– Liaison statique: la résolution de liens se fait de
manière statique au moment de la compilation en
utilisant le type de la référence de l’objet.
– Liaison dynamique: la résolution de liens se fait au
moment de l’exécution en utilisant le type de l’objet.
• Résolution de liens et classes membres:
– Méthode statique d’une super classe membre
statique: liaison statique
– Méthode non statique d’une super classes
membres: liaison dynamique
107
Résolution de liens
Exemple 12: considérons la classe Outer suivante
comportant quatre classes membres.
class Outer{
public static class StatInner{
public static void print(){[Link]("StatInner");}
}
public static class SubStatInner extends StatInner{
public static void print(){[Link]("SubStatInner");}
}
public class NonStatInner{
public void print(){[Link]("NonStatInner");}
}
public class SubNonStatInner extends NonStatInner{
public void print(){[Link]("SubNonStatInner");}
}
}
108
Groupe: CPI2-ISIMM 54
Dr Imed ABBASSI 28/02/2019
Résolution de liens
• Le programme suivant présente des liaisons
statiques et dynamiques.
public class Main{
public static void main(String[] args){
[Link] A=new [Link]();
[Link] B=new [Link]();
[Link] C=new Outer().new NonStatInner();
[Link] D=new Outer().new SubNonStatInner();
[Link](); // StatInner
[Link](); // StatInner
[Link](); // NonStatInner
[Link](); // SubNonStatInner
}
}
109
Chapitre 4: Les interfaces graphiques
1. Introduction
2. Packages AWT et SWING
3. Gestionnaires de disposition
4. Gestion des événements
110
Groupe: CPI2-ISIMM 55
Dr Imed ABBASSI 28/02/2019
Introduction
• Il existe deux grandes familles de composant graphique
en JAVA:
– L’API AWT (Abstract Window Toolkit, JDK 1.1)
– L’API Swing (JDK/SDK 1.2)
• Les deux API AWT et SWING utilisent des concepts
semblables, mais pas totalement identiques.
• L’API Swing est apparue dès Java 2, en proposant des
composants dits "légers", indépendants du système
d’exploitation, et dotés de propriétés plus riches que
ceux de AWT.
Il est fortement conseillé d’utiliser les composants
Swing et ce cours sera donc centré sur Swing.
111
Introduction
• Les composants Swing forment une nouvelle hiérarchie
parallèle à celle de l'AWT.
• L'ancêtre de cette hiérarchie est le composant
JComponent.
• Presque tous ces composants sont écrits en pure Java :
ils ne possèdent aucune partie native sauf ceux qui
assurent l'interface avec le système d'exploitation :
JApplet, JDialog, JFrame, et JWindow.
• Cela permet aux composants de toujours avoir la même
apparence quel que soit le système sur lequel
l'application s'exécute.
112
Groupe: CPI2-ISIMM 56
Dr Imed ABBASSI 28/02/2019
Conteneurs
• Il y a 3 sortes de containers lourds (un autre,
JWindow, est plus rarement utilisé) :
– JFrame fenêtre pour les applications
– JApplet pour les applets
– JDialog pour les fenêtres de dialogue
• Pour construire une interface graphique avec
Swing, il faut créer un (ou plusieurs) conteneur
lourd et placer à l’intérieur les composants légers
qui forment l'interface graphique
113
Conteneurs
• Les conteneurs « intermédiaires » légers :
– JPanel
– JScrollPane
– JSplitPane
– JTabbedPane
– Box (ce dernier est léger, mais n’hérite pas de JComponent)
JPanel: la classe mère des conteneurs intermédiaires les
plus simples.
• sert à regrouper des composants dans une zone d'écran.
• peut servir de composant dans lequel on peut dessiner
ce que l’on veut, ou faire afficher une image (par la
méthode paintComponent).
114
Groupe: CPI2-ISIMM 57
Dr Imed ABBASSI 28/02/2019
Conteneurs
115
Conteneurs
Jframe:
• Une classe permet la création des fenêtres disposant
d’un titre, une taille modifiable et éventuellement un
menu.
• Il possède plusieurs constructeurs:
– JFrame() : Constructeur par défaut
– JFrame(String titre) : Création d’une instance en précisant le Titre
de la fenêtre.
• Les méthodes les plus utilisées de cette classe sont :
– setSize(int, int): permets de préciser les dimensions de la
Fenêtre.
– setVisible (boolean) : par défaut la fenêtre est invisible, pour la
rendre visible on fait appel à cette méthode.
– setResizable(boolean): par défaut la fenêtre peut changer de
dimension. Pour la rendre figée, on utilise cette méthode.
– setTitle (String titre): permets de définir le titre de fenêtre.
116
Groupe: CPI2-ISIMM 58
Dr Imed ABBASSI 28/02/2019
Conteneurs
• Il est possible de préciser comment un objet Jframe
réagit à sa fermeture grâce à la méthode
setDefaultCloseOperation():
[Link](param);
Où la valeur du paramètre « param » est décrite comme
suit:
Paramètre Rôle
Jframe.DISPOSE_ON_CLOSE détruit la fenêtre
Jframe.DO_NOTHING_ON_CLOSE rend le bouton de fermeture
inactif
Jframe.HIDE_ON_CLOSE cache la fenêtre
Jframe.EXIT_ON_CLOSE Quitte le programme
117
Conteneurs
Exemple 1:
import [Link].*;
public class JFexemple1{
public static void main (String args[]){
JFrame fen = new JFrame() ;
[Link] (300, 150) ;
[Link](JFrame.EXIT_ON_CLOSE);
[Link] ("Ma première fenêtre");
[Link] (true);
}
}
118
Groupe: CPI2-ISIMM 59
Dr Imed ABBASSI 28/02/2019
Conteneurs
Création d’une classe fenêtre personnalisée:
class nomFenetre extends JFrame
{
public nomFenetre ([params]){….}
….
}
Exemple 2:
class MaFenetre extends JFrame{
public MaFenetre () {
setTitle ("Ma premiere fenetre") ;
setSize (300, 150) ;
}
}
119
Composants graphiques
• Pour utiliser un composant, il faut créer un nouvel objet
représentant le composant et l'ajouter à un de type
conteneur avec la méthode add().
• Exemples de composants graphiques :
– JLabel : les étiquettes
– JButton : les boutons
– JTextComponent: les champs de textes
– JTable: les tableaux à deux dimensions
– JCheckBox: les cases à cocher
– JRadioButton: les bouton radio
– JComboBox: les listes déroulantes
• Ces composants sont disponibles dans le package
« [Link].* ».
120
Groupe: CPI2-ISIMM 60
Dr Imed ABBASSI 28/02/2019
Composants graphiques
Boutons: Jbutton
• Cette classe possède deux constructeurs :
– JButton() : crée un bouton sans Nom (label).
– JButton(String): crée un bouton disposant d’un label.
• Quelques méthodes utiles :
– void setLabel(String) : affecte un libellé au bouton.
– void setSize(int, int): affecte une dimension au bouton.
121
Composants graphiques
Labels: Jlabel
• Cette classe possède deux constructeurs :
– JLabel() : crée une zone Label vide.
– JLabel(String): crée une zone label avec le texte
passer comme paramètre.
• Quelques méthodes :
– void setText(String) : modifie la zone de texte du label.
– void setSize(int, int): modifie la dimension du label.
122
Groupe: CPI2-ISIMM 61
Dr Imed ABBASSI 28/02/2019
Composants graphiques
Zones de texte: Il faut utiliser un objet de l’une des classes
suivantes:
– JTextField: une classe permet de créer des champs de texte sur
une seule ligne.
– JPasswordField: une classe permet de créer des champs de saisie
de mot de passe.
– JTextArea: une classe permet de créer des champs de texte sur
plusieurs lignes.
• Ces trois classes sont des sous-classes JTextComponent
qui offre les méthodes suivantes:
– String getText() : récupération du texte du champ
– void setText(String text) : modification du contenu du champ de
texte.
– Boolean isEditable() : true si le champ est modifiable, false sinon
– void setEditable(boolean b) : modification de la propriété
modifiable.
123
Composants graphiques
Les cases à cocher: JCheckBox.
• Les constructeurs:
– JCheckBox(String label)
– JCheckBox(String label, Icon icon)
• Quelques méthodes utiles:
– JCheckBox(String label, boolean state) : Construis
une case à cocher avec l’étiquette donnée et l’état initial.
– boolean isSelected()
– void setSelected(boolean state)
124
Groupe: CPI2-ISIMM 62
Dr Imed ABBASSI 28/02/2019
Composants graphiques
Les boutons radio: JRadioButton.
• Les constructeurs:
– JRadioButton(String label, Icon icon) : Construis un bouton radio,
non sélectionné au départ.
– JRadioButton(String label, boolean state) : Construis un bouton
radio avec le libellé donné et l’état initial.
• Quelques méthodes utiles:
– void add(AbstractButton b) : Ajoute le bouton au groupe.
– ButtonModel getSelection() : Renvoie le modèle du bouton
sélectionné.
125
Composants graphiques
Les listes déroulantes: JComboBox
• Constructeur de la classe :
– JComboBox (Object[] ListComposants)
• Quelques méthodes utiles:
– void addItem(Object item) : Ajoute un élément dans la liste.
– void insertItemAt(Object item, int index) : Insère un élément dans
la liste à la position donnée par l’indice.
– void removeItem(Object item) : Supprime un élément de la liste.
– void removeItemAt(int index) : Supprime l’élément dans la liste à
la position donnée par l’indice.
126
Groupe: CPI2-ISIMM 63
Dr Imed ABBASSI 28/02/2019
Composants graphiques
Les tables bidimensionnelles: JTable
• Constructeurs de la classe :
– JTable()
– JTable(int numRows, int numColumns)
– JTable(Object[][] rowData, Object[] columnNames)
– JTable(Vector<? extends Vector> rowData, Vector<?>
columnNames)
…
127
Composants graphiques
• Méthodes de la classe JTable:
– void addColumn(TableColumn aColumn)
– void addColumnSelectionInterval(int index0, int index1)
– void addRowSelectionInterval(int index0, int index1)
…
Exemple 3:
import [Link].*;
public class TableExample {
public static void main() {
JFrame f=new JFrame();
String data[][]={ {"101","Amit","670000"},{"102","Jai","780000"},
{"101","Sachin","700000"}};
String column[]={"ID","NAME","SALARY"};
JTable jt=new JTable(data,column);
JScrollPane sp=new JScrollPane(jt); [Link](sp); [Link](true);
new TableExample();
}}
128
Groupe: CPI2-ISIMM 64
Dr Imed ABBASSI 28/02/2019
Gestionnaires de disposition
• Un gestionnaire de disposition (layout manager) permet de
spécifier comment les composants sont insérés dans le
conteneur.
• Types des gestionnaires de disposition:
– BorderLayout : placer aux 5 points cardinaux (NORTH, SOUTH,
WEST, ESAT et CENTER).
– FlowLayout : placer à la suite
– GridLayout : placer dans une grille
– BoxLayout : placer verticalement ou horizontalement
– GridBagLayout : placements complexes
• Chaque gestionnaire de disposition implémente l'interface
LayoutManager du package AWT.
129
Gestionnaires de disposition
• La création d’une fenêtre se fait en cinq étapes:
1. La création du conteneur:
JPanel contentPane=new JPanel();
2. la création du gestionnaire de disposition:
Layout_Name lname=new Layout_Name([<args>]);
[Link](lname);
3. Ajout des composants graphiques au conteneur avec les
contraintes du layout manager.
4. Modification du conteneur de la fenêtre comme suit:
[Link](contentPane);
5. Les opérations de base pour chaque fenêtre
[Link](); [Link](titre);
[Link](EXIT_ON_CLOSE);
[Link](true);
130
Groupe: CPI2-ISIMM 65
Dr Imed ABBASSI 28/02/2019
Gestionnaires de disposition: FlowLayout
• Les composants d'un conteneur sont placés ligne par ligne
et de gauche à droite.
– Chaque ligne est complétée progressivement jusqu'à être remplie,
puis passe à la suivante. Par défaut, chaque ligne est centrée.
– Le conteneur JPanel possède un FlowLayout par défaut.
• Les constructeurs de FlowLayout
– FlowLayout()
– FlowLayout(int align)
– FlowLayout(int align, int hgap, int vgap)
Avec:
– align : L’une des constantes d’alignement LEFT, CENTER ou
RIGHT.
– hgap : L’intervalle horizontal en pixels à utilise.
– vgap : L’intervalle vertical en pixels à utiliser.
131
Gestionnaires de disposition: FlowLayout
Redimensionnement
Redimensionnement
132
Groupe: CPI2-ISIMM 66
Dr Imed ABBASSI 28/02/2019
Gestionnaires de disposition: FlowLayout
Exemple 4: considérons le programme suivant.
public class TestFlowLayout1 extends JFrame{
public TestFlowLayout(){
JPanel pane=new JPanel(new FlowLayout());
JButton b1=new JButton("Bouton 1");
JButton b2=new JButton("Bouton 2");
JButton b3=new JButton("Bouton 3");
[Link](b1); [Link](b2); [Link](b3);
setContentPane(pane);
[Link](); [Link](true); [Link]("Exemple FlowLayout");
[Link](EXIT_ON_CLOSE);
}
public static void main(String[] args){ new TestFlowLayout();}
}
133
Gestionnaires de disposition: FlowLayout
• Ce programme fournit le résultat suivant:
134
Groupe: CPI2-ISIMM 67
Dr Imed ABBASSI 28/02/2019
Gestionnaires de disposition: BorderLayout
• Les composants d'un conteneur sont structurés en cinq
zones:
– North: [Link]
– South: [Link]
– East: [Link])
– West: [Link])
– Center: [Link]
• BorderLayout consacre tout l'espace du conteneur aux
composants.
• Le composant du milieu dispose de la place inutilisée par
les autres composants.
• Les constructeurs principaux de BorderLayout:
– BorderLayout( )
– BorderLayout (int hgap,int vgap): précise l'espacement horizontal et vertical
entre les composants.
135
Gestionnaires de disposition: BorderLayout
Exemple 5: un programme TestBorderLayout
public class TestBorderLayout extends JFrame{
//Création des composants graphiques
JButton b1=new JButton("Bouton 1");
JButton b2=new JButton("Bouton 2");
JButton b3=new JButton("Bouton 3");
JButton b4=new JButton("Bouton 4");
JButton b5=new JButton("Bouton 5");
public TestBorderLayout(){
JPanel contentPane=new JPanel(new BorderLayout());
/*Ajout des composants au conteneur avec les contraintes du layout manager*/
[Link](b1, [Link]);
[Link](b2,[Link]);
[Link](b3, [Link]);
[Link](b4, [Link]);
[Link](b5, [Link]);
136
Groupe: CPI2-ISIMM 68
Dr Imed ABBASSI 28/02/2019
Gestionnaires de disposition: BorderLayout
//Modification du contentPane de la fenêtre
[Link](contentPane);
//Les opérations de base pour chaque fenêtre
[Link]();
[Link]("Exemple Border Layout ");
[Link](EXIT_ON_CLOSE);
[Link](true);
}
//Appel à la fenêtre
public static void main(String[] args){
new TestBorderLayout();
}
}
137
Gestionnaires de disposition: BorderLayout
• Ce programme fournit le résultat suivant:
138
Groupe: CPI2-ISIMM 69
Dr Imed ABBASSI 28/02/2019
Gestionnaires de disposition: BorderLayout
Exemple 6: considérons le programme suivant.
public class TestBorderLayout extends JFrame{
public TestBorderLayout(String s){
super(s);
add(new JButton("Nord"), [Link]);
add(new JButton("Sud"),[Link]);
add(new JButton("Centre"), [Link]);
add(new JButton("Droite"), [Link]);
add(new JButton("Gauche"), [Link]);
pack(); setDefaultCloseOperation(EXIT_ON_CLOSE); setVisible(true);
}
public static void main(String[] args){
TestBorderLayout testBL = new TestBorderLayout("Exemple Border Layout");
}
}
139
Gestionnaires de disposition: BorderLayout
• Ce programme donne le résultat suivant.
Le BorderLayout est le gestionnaire par défaut du
conteneur Jframe.
140
Groupe: CPI2-ISIMM 70
Dr Imed ABBASSI 28/02/2019
Gestionnaires de disposition: GridLayout
• Les composants d'un conteneur sont placés sous forme
d’une grille similaire à un tableau à deux dimensions.
• Dans une grille, les composants ont la même taille. Ils
s’agrandissent et diminuent tout en conservant des tailles
identiques.
• Les constructeurs principaux de GridLayout :
– GridLayout(int rows, int columns)
– GridLayout(int rows, int columns, int hgap, int vgap)
Où
– rows : Le nombre de lignes dans la grille
– columns : Le nombre de colonnes dans la grille.
– hgap : L’intervalle horizontal en pixels (les valeurs négatives
provoquent un chevauchement).
– vgap : L’intervalle vertical en pixels (les valeurs négatives
provoquent un chevauchement).
141
Gestionnaires de disposition: GridLayout
Exemple 7: un programme TestGridLayout
public class TestGridLayout extends JFrame{
public TestGridLayout(){
JPanel pane=new JPanel(new GridLayout(3,3));
[Link](new JButton("1")); [Link](new JButton("2"));
[Link](new JButton("3"));[Link](new JButton("4"));
[Link](new JButton("5"));[Link](new JButton("6"));
[Link](new JButton("7"));[Link](new JButton("8"));
[Link](new JButton("9"));
[Link](pane);
[Link](); [Link](true);
[Link]("Exemple GridLayout ");
[Link](EXIT_ON_CLOSE);
}
public static void main(String[] args){new TestGridLayout ();}
}
142
Groupe: CPI2-ISIMM 71
Dr Imed ABBASSI 28/02/2019
Gestionnaires de disposition: GridLayout
• Résultats d’exécution du programme TestGridLayout:
143
Gestionnaires de disposition: BoxLayout
• Les composants d'un conteneur sont affichés en ligne ou en
colonne, selon leur taille préférée et selon l’ordre d’insertion
et de placement dans le conteneur.
• Le constructeur du BoxLayout:
– public BoxLayout(Container target, int axis)
Avec
– target : le conteneur cible à qui sera affecter le BoxLayout
– axis : L’alignement des composants. Il peut être l’une des valeurs
suivantes :
• BoxLayout.X_AXIS : alignement selon l’axe de X.
• BoxLayout.Y_AXIS : alignement selon l’axe de Y.
• BoxLayout.LINE_AXIS : alignement rangé en ligne.
• BoxLayout.PAGE_AXIS :alignement rangé en colonne.
144
Groupe: CPI2-ISIMM 72
Dr Imed ABBASSI 28/02/2019
Gestionnaires de disposition: BoxLayout
Exemple 8: un programme TestBoxLayout
public class TestBoxLayout extends JFrame{
//Création des composants graphiques
JButton b1=new JButton("Bouton 1");
JButton b2=new JButton("Bouton 2");
JButton b3=new JButton("Bouton treeeeeeeeeeees long 3");
JButton b4=new JButton("Bouton treeeeeeeeeeees long 4");
JButton b5=new JButton("B5");
JButton b6=new JButton("B6");
public TestBoxLayout (){
JPanel contentPane=new JPanel();
//Création du layout manager
BoxLayout bl=new BoxLayout(contentPane, BoxLayout.Y_AXIS);
//Affectation du layout manager au conteneur
[Link](bl);
145
Gestionnaires de disposition: BoxLayout
/*Ajout des composants graphiques au conteneur avec les contraintes du layout
manager
*/
[Link](b1); [Link](b2);
[Link](b3); [Link](b4);
[Link](b5); [Link](b6);
//Modification du contentPane de la fenêtre
[Link](contentPane);
//Les opérations de base pour chaque fenêtre
[Link](); [Link](true);
[Link]("Exemple BoxLayout ");
[Link](EXIT_ON_CLOSE);
}
//Appel à la fenêtre
public static void main(String[] args){new TestBoxLayout ();}
}
146
Groupe: CPI2-ISIMM 73
Dr Imed ABBASSI 28/02/2019
Gestionnaires de disposition: BoxLayout
• Résultats d’exécution du programme TestBoxLayout
147
Gestionnaires de disposition: BoxLayout
• Dans un conteneur formaté avec BoxLayout, on peut ajouter
des glues et des struts (des composants vides) et ainsi que
des zones rigides (rigid area).
• Les composants peuvent être insérés dans une boite par la
méthode suivante: nom_Box.add(nomBoutton)
• Méthodes statiques de création de boites:
– createHorizontalBox (): une méthode de création des
boites permettant de placer les composants d’une
manière horizontale.
– createVerticalBox(): une méthode de création des
boites permettant de placer les composants d’une
manière verticale.
148
Groupe: CPI2-ISIMM 74
Dr Imed ABBASSI 28/02/2019
Gestionnaires de disposition: BoxLayout
• Autres méthodes utiles:
– [Link](20)
– [Link](30)
– createRigidArea(new Dimension(3,5))
– [Link]()
– [Link]()
Exemple 9: considérons la fenêtre suivante.
149
Gestionnaires de disposition: BoxLayout
• Cette interface peut être produite par le programme
suivante.
import [Link].*;
import [Link].*;
import [Link].*;
public class TestBoxLayout extends JFrame{
public TestBoxLayout (){
//On crée un conteneur avec gestion horizontale
Box b1 = [Link]();
[Link](new JButton("Bouton 1"));
Box b2 = [Link]();
[Link](new JButton("Bouton 2")); [Link](new JButton("Bouton 3"));
Box b3 = [Link]();
[Link](new JButton("Bouton 4")); [Link](new JButton("Bouton 5"));
[Link](new JButton("Bouton 6"));
150
Groupe: CPI2-ISIMM 75
Dr Imed ABBASSI 28/02/2019
Gestionnaires de disposition: BoxLayout
//On crée un conteneur avec gestion verticale
Box b4 = [Link]();
[Link](b1);[Link](b2);[Link](b3);
[Link]().add(b4);
//Les opérations de base pour chaque fenêtre
[Link]();
[Link]("Exemple BoxLayout ");
[Link](EXIT_ON_CLOSE);
[Link](true);
}
//Appel à la fenêtre
public static void main(String[] args){
new TestBoxLayout ();
}
}
151
Gestionnaires de disposition: GridBagLayout
• Un GridBagLayout est comme un GridLayout sans ses
limitations. Les lignes et les colonnes peuvent avoir des
tailles variables (joindre des cellules adjacentes, occupe
toute une ligne…).
• Ce gestionnaire est utilisé comme suit:
1. Créez un objet de type GridBagLayout. Ne lui indiquez pas le
nombre de lignes et de colonnes que la grille sous-jacente doit
posséder.
2. Définissez cet objet comme étant le gestionnaire de mise en forme
pour le composant.
3. Pour chaque composant, créez un objet de type
GridBagConstraints. Définissez les valeurs de champ de l’objet
GridBagConstraints pour spécifier de quelle façon les composants
sont disposés à l’intérieur du GridBag.
4. Ajoutez enfin le composant avec les contraintes au moyen d’un
appel : add(component, constraints);
152
Groupe: CPI2-ISIMM 76
Dr Imed ABBASSI 28/02/2019
Gestionnaires de disposition: GridBagLayout
• Les contraintes qui définissent l’emplacement du composant
dans la grille:
– gridx et gridy : spécifient les positions de colonne et de ligne du
coin supérieur gauche du composant à ajouter.
– gridwidth et gridheight : déterminent le nombre de colonnes et de
lignes que le composant occupe.
• RELATIVE : on occupe toute la zone jusqu’au prochain composant fixe.
• REMAINDER : la zone est la dernière de la ligne ou de la colonne.
• Entier : par défaut il est égal à 1 (une cellule).
– weightx et weighty : chaque composant peut demander de l'espace
en plus au moyen de poids. Par défaut il est égal a 0, le champ ne
s’agrandit ou ne diminue jamais au de là de sa taille initiale.
– fill : Si vous ne voulez pas qu’un composant s’étire et remplisse
toute la zone, vous devez définir la contrainte fill.
153
Gestionnaires de disposition: GridBagLayout
– anchor : Indique l’alignement du composant à l’intérieur de la
cellule. L’une des positions absolues suivantes
• CENTER,
• NORTH,
• NORTHEAST,
• EAST,
• SOUTHEAST,
• SOUTH,
• SOUTHWEST,
• WEST ou
• NORTHWEST
154
Groupe: CPI2-ISIMM 77
Dr Imed ABBASSI 28/02/2019
Gestionnaires de disposition: GridBagLayout
• Les contraintes qui définissent l’emplacement du composant
dans la grille (suite):
– insets : Vous pouvez entourer un composant d’un espace vierge
supplémentaire.
• left,
• top,
• right
• bottom de l’objet Insets avec les valeurs d’espace que vous voulez
avoir autour du composant.
– ipadx et ipady : définissent le remplissage interne. Ces valeurs sont
ajoutées aux largeur et hauteur minimales du composant. Cela
garantit que le composant ne diminuera pas jusqu’à sa taille
minimale.
155
Gestionnaires de disposition: GridBagLayout
Exercice 2: On voudrait réaliser l’interface de la figure
suivante.
• On doit procéder comme suit:
– Décomposer la figure en cellule
– Une fois la décomposition faite, il faut :
• Créer l’objet GridBagContraint.
• Pour chaque composant faire :
– Déterminer la ou les contraintes
– Ajouter le composant au panel
• Afficher le panel.
156
Groupe: CPI2-ISIMM 78
Dr Imed ABBASSI 28/02/2019
Gestionnaires de disposition: GridBagLayout
• L’interface est réalisée par le programme Java suivant.
import [Link].*;
import [Link].*;
public class TestBoxLayout extends JFrame{
JButton b1 = new JButton("b1");
JButton b2 = new JButton("b2");
JButton b3 = new JButton("b3");
JButton b4 = new JButton("b4");
JButton b5 = new JButton("b5");
JButton b6 = new JButton("b6");
JButton b7 = new JButton("b7");
JButton b8 = new JButton("b8");
public TestBoxLayout (){
//On crée un conteneur avec gestion GridBagLayout
JPanel contentPane=new JPanel(new GridBagLayout());
GridBagConstraints gbc=new GridBagConstraints();
[Link]=0;[Link]=0; [Link]=2; [Link]=[Link];
[Link](b1, gbc);
157
Gestionnaires de disposition: GridBagLayout
[Link]=1; [Link]=0;
[Link]=2; [Link]=1;
[Link]=[Link];
[Link](b2,gbc);
[Link]=3; [Link]=0;
[Link]=1;
[Link]=[Link];
[Link](b3,gbc);
[Link]=1; [Link]=1;
[Link]=1; [Link]=1;
[Link](b4,gbc);
[Link]=2; [Link]=1;
[Link]=[Link];
[Link]=[Link];
[Link](b5,gbc);
158
Groupe: CPI2-ISIMM 79
Dr Imed ABBASSI 28/02/2019
Gestionnaires de disposition: GridBagLayout
[Link]=0; [Link]=2; [Link]=2; Résultats:
[Link]=[Link];
[Link](b6,gbc);
[Link]=2; [Link]=1;
[Link](b7,gbc);
[Link]=3;[Link](b8,gbc);
[Link](contentPane);
//Les opérations de base pour chaque fenêtre
[Link]();
[Link]("Exemple GridBagLayout ");
[Link](EXIT_ON_CLOSE);
[Link](true);
}
//Appel à la fenêtre
public static void main(String[] args){
new TestBoxLayout ();
}
}
159
Gestion des événements
• L'utilisateur utilise le clavier et la souris pour intervenir sur le
déroulement du programme.
• Le système d’exploitation doit engendrer des événements à
partir des actions de l’utilisateur.
• Le programme doit donc lier des actions à ces événements.
Deux types d'événements:
– Événements de bas niveau, générés directement par des
actions élémentaires de l’utilisateur.
– Événements « logiques » de plus haut niveau,
engendrés par plusieurs actions élémentaires, qui
correspondent à une action complète de l'utilisateur.
160
Groupe: CPI2-ISIMM 80
Dr Imed ABBASSI 28/02/2019
Gestion des événements
• Les événements sont représentés par des instances de
sous-classes de [Link].
• Événements liés directement aux actions de l’utilisateur :
– KeyEvent : appuie sur une touche, relâchement …
– MouseEvent : click par le bouton de la sourie, …
• Événements de haut niveau :
– FocusEvent : élément ayant gagné le focus ou l’ayant perdu.
– WindowEvent : fenêtre ouverte, fermée, iconifiée, désiconifiée,
activée ou désactivée.
– ActionEvent : déclenchement d’une action.
– ItemEvent : choix dans une liste, dans une boîte à cocher
– ComponentEvent : composant déplacé, retaillé, caché ou montré.
– TextEvent: texte inséré dans un document.
161
Gestion des événements
Écouteurs: conçus pour traiter un certain type d'événements.
• Chacun des composants graphiques a ses écouteurs.
• Un composant peut avoir plusieurs écouteurs;
• À chaque type d’écouteur correspond une interface que doit
implémenter la classe de l’écouteur ; par exemple
ActionListener, MouseListener ou KeyListener
Propriétés des écouteurs:
– Un écouteur doit s’enregistrer auprès des composants qu’il
souhaite écouter, en lui indiquant le type d’événement qui
l’intéresse.
– Il peut ensuite se désenregistrer
– Un écouteur peut écouter plusieurs composants.
162
Groupe: CPI2-ISIMM 81
Dr Imed ABBASSI 28/02/2019
Gestion des événements
• La classe ActionEvent
– Cette classe décrit des événements de haut niveau qui vont le plus
souvent déclencher un traitement (une action) :
• clic sur un bouton
• return dans une zone de saisie de texte
• choix dans un menu
• Interface ActionListener
– Un objet écouteur intéressé par les événements de type « action »
(classe ActionEvent) doit appartenir à une classe qui implémente
l’interface [Link]
• Définition de ActionListener :
public interface ActionListener extends EventListener{
void actionPerformed(ActionEvent e);
}
163
Gestion des événements
• Inscription de l’écouteur:
– On inscrit un tel écouteur auprès d’un composant nommé composant
par la méthode suivante:
[Link](écouteur);
– On précise ainsi qu’écouteur est intéressé par les événements
ActionEvent engendrés par composant.
• Message déclenché par un événement:
– Un événement unActionEvent engendré par une action de
l’utilisateur sur bouton provoquera l'envoi d'un message
actionPerformed à tous les écouteurs :
[Link](unActionEvent);
– Ces messages sont envoyés automatiquement à tous les écouteurs
qui se sont enregistrés auprès du bouton.
164
Groupe: CPI2-ISIMM 82
Dr Imed ABBASSI 28/02/2019
Gestion des événements
• Les événements utilisateurs sont gérés par plusieurs
interfaces EventListener.
• Les interfaces EventListener permettent à un composant de
générer des événements utilisateurs.
• Une classe doit contenir une interface auditeur pour chaque
type de composant :
– ActionListener : clic de souris ou enfoncement de la touche Enter.
– ItemListener : utilisation d'une liste ou d'une case à cocher.
– MouseMotionListener : événement de souris.
– WindowListener : événement de fenêtre.
165
Gestion des événements
• L’implémentation d’un écouteur se fait en 4 étapes:
1. Importer le groupe de classe [Link]
2. la classe doit déclarer qu'elle utilisera une ou plusieurs interfaces
d'écoute
3. Appel à la méthode addXXX() pour enregistrer l'objet qui gérera
les événements XXX du composant
Il faut configurer le composant pour qu'il possède un "écouteur"
pour l'événement utilisateur concerné.
4. Implémenter les méthodes déclarées dans les interfaces : chaque
auditeur possède des méthodes différentes qui sont appelées pour
traiter leurs événements. Par exemple, l'interface ActionListener
envoie des événements à une classe nommée actionPerformed( ).
• Remarques:
– Il est possible d'enregistrer un même listener pour
plusieurs composants
– getSource() permet d'obtenir le composant ayant créé
l'évènement: public Object getSource()
166
Groupe: CPI2-ISIMM 83
Dr Imed ABBASSI 28/02/2019
Chapitre 5: Accès aux BDD en java
1. Introduction
2. Accès aux BDD
3. Objets d’accès aux données
167
Introduction
• JDBC : Java Data Base Connectivity
• Framework permettant l'accès aux bases de
données (BDD) relationnelles dans un programme Java.
• Caractéristiques de JDBC:
– Constitué d’un ensemble de classes et d’interfaces permettant
l’interaction avec les BDD relationnelles:
• Sélection de données dans des tables
• Création de tables et insertion d'éléments dans les tables
• Gestion des transactions
– Indépendant du type de BDD (mySQL, Oracle, Postgres ...)
– Fournie par les packages [Link] et [Link].
• L’accès aux BDD se fait par des objets en se servant du
Framework JDBC;
168
Groupe: CPI2-ISIMM 84
Dr Imed ABBASSI 28/02/2019
Principes d'accès à une BDD
• Les principes généraux d'accès à une BDD sont les
suivants:
– Etape 1: le chargement du driver de la BDD.
– Etape 2: la connexion à la base de données en se servant des
classes Connection et DriverManager.
– Etape 3: l’exécution des commandes SQL en se servant de la classe
Statement.
– Etape 4: l’inspection des résultats (si disponible) en se servant de la
classe ResultSet.
– Etape 5: la fermeture de l’accès à la BDD.
169
Chargement du driver de la BDD
• Types de drivers JDBC:
– JDBC-ODBC bridge driver: c’est un pont entre JDBC et ODBC.
ODBC (Open Data Base Connectivity) est une API de Windows
permettant d'accéder à diverses bases de données .
– Native-API partly-Java driver : ce driver fait appel à des fonctions
natives (non-Java) de l’API du SGBDR qui sont souvent fournis par
le constructeur.
– JDBC-Net all-Java driver : ce driver interagit avec une API réseau
générique et communique avec une application intermédiaire
(middleware) sur le serveur.
– Native-protocol all-Java driver : ce driver utilise le protocole réseau
du SGBDR. Il interagit avec la base de données via des soquets
généralement fournis par l’éditeur.
170
Groupe: CPI2-ISIMM 85
Dr Imed ABBASSI 28/02/2019
Chargement du driver de la BDD
• JDBC-ODBC bridge : les méthodes du driver JDBC font appel à des fonctions
en langage C d'un driver ODBC.
Application java
Driver JDBC
Driver ODBC
SGBD
• Native-API partly-Java: les méthodes du driver JDBC font appel à des fonctions
d'une bibliothèque écrite dans un autre langage que Java.
Application java
Partie JAVA
Driver
Partie Native
Protocole du SGBDR
SGBD
171
Chargement du driver de la BDD
• JDBC-Net all-Java: les méthodes du driver JDBC se connectent par
soquet au serveur middleware et lui envoient les requêtes SQL.
Application java
Driver en JAVA
Protocole du middleware
Serveur middleware
SGBD
• Native-protocol all-Java: les méthodes du driver JDBC utilisent des
soquets pour communiquer avec le SGBD.
Application java
Driver en JAVA
Protocole réseau du SGBD
SGBD
172
Groupe: CPI2-ISIMM 86
Dr Imed ABBASSI 28/02/2019
Chargement du driver de la BDD
• Chargement du driver:
– Pour se connecter à une base de données via ODBC, il faut tout
d'abord charger le pilote JDBC-ODBC en utilisant la méthode
forName de la classe Class.
– Ce traitement charge le pilote et créer une instance de cette classe.
– La méthode static forName() de la classe Class peut lever
l'exception [Link].
• Exemples:
– [Link]("[Link]");
– [Link]("[Link]");
173
Connexion à la BDD
• La connexion à une BDD set fait en créant un objet de la
classe Connection en lui précisant sous forme d'URL la
base à accéder:
Connection cnx=[Link] (URL, USER,
PASSWORD);
Avec :
– URL désigne une chaîne de caractères que le driver JDBC de
SGBD utilise pour se connecter à une base de données.
– USER désigne un utilisateur de la base de données.
– PASSWORD désigne le mot de passe de connexion à la base de
l’utilisateur.
• Remarque: la méthode getConnection peut lever une
exception de la classe [Link]
174
Groupe: CPI2-ISIMM 87
Dr Imed ABBASSI 28/02/2019
Connexion à la BDD
Exemple 1: connexion à une BDD oracle
import [Link].*;
...
public static void main (String [] args){
String url="jdbc:oracle:thin:@localhost:1521:xe";
String user="abbassi";
String password="manager";
Connection cnx;
try {
[Link]("[Link]");
cnx= [Link](URL, user,password);
...
} catch (Exception e){[Link]([Link]());}
...
}
...
175
Connexion à la BDD
Exemple 2: connexion à une BDD mysql
import [Link].*;
...
public static void main(String args[]){
String url= "jdbc:mysql://localhost:3306/mybd";
String user="root";
String password="root";
try{
[Link]("[Link]");
Connection con=[Link](URL, user, password);
...
} catch (Exception e){[Link]([Link]());}
...
}
...
176
Groupe: CPI2-ISIMM 88
Dr Imed ABBASSI 28/02/2019
Exécution des commandes SQL
• L’accès à la BDD se fait à travers un objet Statement que
l’on obtient depuis l’objet Connexion.
Statement stmt = [Link]();
• Cet objet Statement sert d’intermédiaire pour exécuter les
requêtes SQL.
• Les méthodes d’exécution de requêtes SQL:
– executeQuery : pour exécuter les requêtes de sélection
(SELECT).
– executeUpdate : pour exécuter les requêtes INSERT, UPDATE,
DELETE, CREATE TABLE et DROP TABLE. Requête de mise à
jour dans le cas général.
– execute : pour exécuter quelques cas rares (exécution de
procédures stockées)
• Remarque: les méthodes d’exécution de requêtes SQL
peuvent générer des exceptions de type SQLException
177
Inspection des résultats
• L’inspection des résultats d’une requête de sélection se fait
à travers un objet ResultSet:
ResultSet res=[Link](req);
• Les principales méthodes de la classe ResultSet sont :
– getInt(int) / getInt(String) : retourne le contenu de la colonne dont
le numéro / nom est passé en paramètre, sous forme de nombre
entier.
– getFloat(int) / getFloat(String) : retourne le contenu de la colonne
dont le numéro / nom est passé en paramètre sous forme de
nombre flottant.
– getDate(int) / getDate(String) : retourne le contenu (une date) de
la colonne dont le numéro / nom est passé en paramètre.
– next() : se déplace sur le prochain enregistrement : retourne false
si la fin est atteinte.
– Close() : ferme le ResultSet
– getMetaData() : retourne un objet ResultSetMetaData associé au
ResultSet.
178
Groupe: CPI2-ISIMM 89
Dr Imed ABBASSI 28/02/2019
Fermeture d’accès à la BDD
• Une fois le travail est terminé, on ferme toutes les
connexions ouvertes de la BDD.
• On utilise la méthode close() des trois classes
suivantes :
– ResultSet
– Statement
– Connection
• Exemple :
try {
[Link]();
[Link]();
[Link]();
} catch(SQLException e){}
179
Patron DAO
DAO: Data Access Object
• Utilités:
– Permet de faire le lien entre la couche d'accès aux données et la
couche métier d'une application (vos classes).
– permet de mieux maîtriser les changements susceptibles d'être
opérés sur le système de stockage des données.
• Mise en œuvre:
– Etape 1: créer, pour chaque table de la base, une classe.
– Etape 2: créer une classe abstraite DAO <T> disposant d’un attribut
de type Connection et des méthodes abstraites suivantes:
• find (int id): la recherche de données dans la base.
• create(T obj): l’insertion des données dans la base.
• update(T obj): la mise à jour de la base.
• delete(T obj): la suppression des données de la base.
– Etape 3: créer, pour chaque table de la base, une classe qui hérite
de DAO <T>.
180
Groupe: CPI2-ISIMM 90
Dr Imed ABBASSI 28/02/2019
Patron DAO
181
Patron DAO: Exemple applicatif
• On considère une BDD constituée des tables suivantes:
– Matiere(code, nomMatiere)
– Enseigner(#code,#matricule, annee)
– Professeur(matricule, nom, prénom)
• Cette BDD est issue du digramme de classes suivant:
182
Groupe: CPI2-ISIMM 91
Dr Imed ABBASSI 28/02/2019
Patron DAO: Exemple applicatif
• Création d’une classe pour la table Matiere.
public class Matiere {
private int code;
private String nomMatiere;
public Matiere(int code, String nom) {
[Link] =code;
[Link] = nom;
}
public int getId() {return code;}
public void setId(int code) {[Link] = code;}
public String getNom() {return nomMatiere;}
public void setNom(String nom) {[Link] = nom;}
}
183
Patron DAO: Exemple applicatif
• Création d’une classe pour la table Professeur.
public class Professeur {
private int matricule;
private String nom,prenom;
public Professeur(int matricule, String nom, String prenom) {
[Link]= matricule;
[Link] = nom;
[Link] = prenom;
}
public int getMatricule() {return matricule;}
public void setMatricule(int matricule) {[Link] = matricule;}
public String getNom() {return nom;}
public void setNom(String nom) {[Link] = nom;}
public String getPrenom() {return prenom;}
public void setPrenom(String prenom) { [Link] = prenom; }
}
184
Groupe: CPI2-ISIMM 92
Dr Imed ABBASSI 28/02/2019
Patron DAO: Exemple applicatif
• Création d’une classe pour la table Enseigner.
public class Enseigner {
private Matiere matiere;
private Professeur prof;
private int annee;
public Enseigner(Matiere m,Professeur p,int annee){
matiere=m; prof=p;
[Link]=annee;
}
public Matiere getMatiere() {return matiere;}
public void setMatiere(Matiere m) {[Link] = m;}
public Professeur getProfesseur() {return prof;}
public void setProfesseur(Professeur p) {[Link] = p;}
public int getAnnee() {return annee;}
public void setAnnee(int annee) {[Link] = annee;}
}
185
Patron DAO: Exemple applicatif
• Création d’une abstraite classe DAO <T>
import [Link].*;
public abstract class DAO<T> {
protected Connection connect = null;
public DAO(Connection conn){
[Link] = conn;
}
public abstract boolean create(T obj);
public abstract boolean delete(T obj);
public abstract boolean update(T obj);
public abstract boolean find(T obj);
}
186
Groupe: CPI2-ISIMM 93
Dr Imed ABBASSI 28/02/2019
Patron DAO: Exemple applicatif
• Création d’une classe nommée MatiereDAO dérivée de
DAO <T> pour la table Matiere:
import [Link].*;
public class MatiereDAO extends DAO<Matiere> {
public MatiereDAO(Connection conn) {super(conn);}
public boolean create(Matiere obj) {. . .}
public boolean delete(Matiere obj) {. . .}
public boolean update(Matiere obj) {. . .}
public boolean find(Matiere m) {
ResultSet res=null;
try{Statement stmt= [Link]();
String req= "SELECT * FROM Matiere WHERE code =";
req+=[Link]();
res=[Link](req);
}catch (SQLException e) {[Link]();}
return (res==null);
}}
187
Patron DAO: Exemple applicatif
• Création d’une classe nommée ProfesseurDAO dérivée de
DAO <T> pour la table Professeur:
import [Link].*;
public class ProfesseurDAO extends DAO<Professeur> {
public ProfesseurDAO(Connection conn) {super(conn);}
public boolean create(Professeur obj) {. . .}
public boolean delete(Professeur obj) {. . .}
public boolean update(Professeur obj) {. . .}
public boolean find(Professeur p) {
ResultSet res=null;
try{Statement stmt= [Link]();
String req= "SELECT * FROM Matiere WHERE matricule =";
req+=[Link]();
res=[Link](req);
}catch (SQLException e) {[Link]();}
return (res==null);
}}
188
Groupe: CPI2-ISIMM 94
Dr Imed ABBASSI 28/02/2019
Patron DAO: Exemple applicatif
• Création d’une classe nommée EnseignerDAO dérivée de
DAO <T> pour la table Enseigner:
import [Link].*;
public class EnseignerDAO extends DAO<Enseigner> {
public EnseignerDAO(Connection conn) {super(conn);}
public boolean create(Enseigner obj) {. . .}
public boolean delete(Enseigner obj) {. . .}
public boolean update(Enseigner obj){. . .}
public boolean find(Enseigner ens) {
ResultSet res=null;
try{Statement stmt= [Link]();
String req= "SELECT * FROM Enseigner WHERE code =";
req+=[Link]().getCode();
req+="and matricule="+[Link]().getMatricule();
req+="annee="+[Link]();
res=[Link](req);
}catch (SQLException e) {[Link]();}
return (res==null); }}
189
Patron DAO: Exemple applicatif
• Création d’une classe nommée EnseignerDAO dérivée de
DAO <T> pour la table Enseigner:
package javaapp8;
public class TestDAO {
public static void main(String[] args) {
JDBC cnx = new JDBC();
Matiere m = new Matiere(0,"Java");
Professeur p = new Professeur(1425," Pascal","Poizat");
Enseigner e= new Enseigner(m, p, 2018);
DAO dao=new EnseignerDAO([Link]);
if () [Link](e);
else [Link]("Le prof. "+[Link]()+" "
+[Link]()
+"a enseigné la matiere"
+[Link]()+" en "+[Link]());
}
}
190
Groupe: CPI2-ISIMM 95