Nothing Special   »   [go: up one dir, main page]

Cours Java

Télécharger au format pdf ou txt
Télécharger au format pdf ou txt
Vous êtes sur la page 1sur 478

Programmation Orienté Objet

Introduction au Langage de Programmation


JAVA
Standard Edition
Dr. HAJJI TARIK
t.hajji@ensam.ac.ma
ENSAM – UMI
2020-2021

ENSAM 2020-2021- T.HAJJI- 1


Sommaire

• Les bases de java


• Les constructeurs
• Généralités sur les structures lexicales de Java
• Héritage
• La gestion des Exceptions
• Complément
• Introduction aux Interfaces graphiques

ENSAM 2020-2021- T.HAJJI- 2


Introduction Générale: L’évolution
Programmation séquentielle
Programmation parallèle
Programmation dynamique
Programmation distribuée
Programmation orienté objet Classes
Structures
de
La
données portabilité
Variables

Typage de données

ENSAM 2020-2021- T.HAJJI- 3


Ch I. JAVA: les bases

I. Généralités sur les objets


• Un objet est une variable améliorée: il stocke les
données, mais on peut effectuer des requêtes sur cet objet
(on demande à l’objet de faire des opérations sur lui-
même), en envoyant un message à cet objet. Ceci est
équivalent à un appel de fonction.
• Chaque objet à son espace mémoire
• Chaque objet a un type précis: c’est-à-dire chaque objet est
une instance (variable) d’une class (type)
• Un programme est ensemble d’objets qui s’envoient des
messages.

ENSAM 2020-2021- T.HAJJI- 4


II. Les bases à connaître
• Java est un langage orienté objet: l'entité de base de
tout code Java est la classe
• Sa syntaxe est proche du langage C
• Il est fourni avec le JDK (Java Developpment Kit)
– Outils de développement
– Ensemble de paquetages très riches et très variés
• Portable grâce à l’exécution par une machine
virtuelle

ENSAM 2020-2021- T.HAJJI- 5


• En Java, tout se trouve dans une classe.
– Il ne peut y avoir de déclarations ou de code en dehors
du corps d'une classe.
• La classe elle même ne contient pas directement du
code.
– Elle contient des déclarations de variables globales, que
l'on appelle des ``attributs'',
– et des méthodes (équivalents à des fonctions).
• Le code se trouve exclusivement dans le corps des
méthodes, mais ces dernières peuvent aussi contenir
des déclarations de variables locales (visibles
uniquement dans le corps de la méthode).

ENSAM 2020-2021- T.HAJJI- 6


III. Mon premier programme en Java

Considérons le code source du programme qui affiche à l’écran


Mon premier programme Java

// Fichier source MonPremProg.java


public class MonPremProg {
// déclaration de données globales
//définition des méthodes
public static void main(String args[]) {
// déclaration des données locales;
System.out.println(" Mon premier programme Java " );
}
}
ENSAM 2020-2021- T.HAJJI- 7
• De manière générale, dans tout programme autonome destiné
à être exécuté doit contenir une méthode particulière
nommée main() définie de la manière suivante:
public static void main(String args[]) {
/* corps de la méthode */
}
• Le paramètre args de la méthode main() est un tableau
d’objets de type String. Il n’est pas utilisé mais, il est exigé
par le compilateur Java.
• La classe contenant la méthode main() doit obligatoirement
être public afin que la machine virtuelle y accès. Dans
l’exemple, le contenu de la classe MonPremProg est réduit à
la définition d’une méthode main().

ENSAM 2020-2021- T.HAJJI- 8


• Un fichier source peut contenir plusieurs
classes mais une seule doit être public(ici
PremProg).
• Le nom du fichier source est identique au
nom de la classe publique qu'il contient,
suivi du suffixe .java, dans l’exemple
MonPremProg.java

ENSAM 2020-2021- T.HAJJI- 9


Compilation
• La compilation d’un programme Java ne traduit pas
directement le code source en fichier exécutable.
• Elle traduit d’abord le code source en un code
intermédiaire appelé « bytecode ».
• C’est le bytecode qui sera ensuite exécuté par une
machine virtuelle (JVM ; Java Virtual Machine).
• Ceci permet de rendre le code indépendant de la
machine qui va exécuter le programme.

ENSAM 2020-2021- T.HAJJI- 10


• Sun fournit le compilateur javac avec le JDK. Dans notre
exemple on exécute:
javac MonPremProg.java

• Cette compilation crée un fichier nommé


«MonPremProg.class» qui contient le bytecode

• On peut désigner le fichier à compiler par un chemin absolu ou


relatif : javac home/user2/MonPremProg.java
• Si un système possède une JVM il peut exécuter tous
les bytecodes (fichiers .class) compilés sur n’importe
qu’el autre système (c’est la notion de la portabilité
de java).
ENSAM 2020-2021- T.HAJJI- 11
Exécution du bytecode
• Le bytecode doit être exécuté par une JVM. Cette
JVM n'existe pas ; elle est simulée par un
programme qui:
– lit les instructions (en bytecode) du programme .class,
– les traduit dans le langage machine relatif à la machine
sur laquelle il sera exécuté.
– Lance leur exécution

ENSAM 2020-2021- T.HAJJI- 12


Exécution avec java
Dans le cas de l’environnement JDK de SUN.

• Pour compiler il suffit d’utiliser la commande javac:


javac MonPremProg.java

• Pour exécuter, Sun fournit le programme java qui simule


une JVM. Il suffira d’utiliser la commande:
java MonPremProg
qui interprète le bytecode de la méthode main() de la classe
MonPremProg

ENSAM 2020-2021- T.HAJJI- 13


L’exécution du programme MonPremProg affiche à l’écran,
comme résultat, la chaîne de caractères:
Mon premier programme Java,
grâce à l’instruction:
System.out.println(" Mon premier programme Java ");

Dans le programme, une ligne qui commence avec


// est un commentaire jusqu’à la fin de la ligne
Une ligne qui commence avec
/* est un commentaire qui peut être étalé sur
plusieurs lignes, et doit terminer avec */

ENSAM 2020-2021- T.HAJJI- 14


III. Les classes en Java
• Une classe décrit un ensemble d’objets qui partagent des
caractéristiques communes.
• On définit une classe pour représenter un problème au lieu
d’utiliser un type de données pour représenter une unité de
stockage dans l’ordinateur.
• On utilise les classes exactement de la même manière que
les types de données prédéfinies.
• On peut créer des variables (objets ou instance) d’un type
particulier.

ENSAM 2020-2021- T.HAJJI- 15


Pour créer un nouveau type d’objets on utilise le mot clé class.
Le canevas de base pour définir un nouveau type de nom
NomDuType est la suivante:

class NomDuType {
/* Corps de la classe: instructions de définitions
des méthodes et des champs */
}

ENSAM 2020-2021- T.HAJJI- 16


Dans la définition de la classe (corps de la classe), on
met deux types d’éléments:

- des données membres de la classe (appelées


champs) qui sont des objets de n’importe quel
type.
- des fonctions membres de la classe (appelées
méthodes).

ENSAM 2020-2021- T.HAJJI- 17


Exemple:
UnTest est une classe (un nouveau type) qui a
3 champs : float, int et boolean.

class UnTest {
float x;
int i;
boolean b;
}
ENSAM 2020-2021- T.HAJJI- 18
Définition des méthodes
La définition de base d’une méthode ressemble à la définition
d’une fonction en C.
typeRetour nomMethode (/* Liste des parametres */) {
/* corps de la méthode */
}
- nomMethode est le nom de la méthode
- Liste de paramètre (arguments de la méthode) donne les
types et les noms des informations qu’on souhaite passer à
la méthode lors de son appel.
- typeRetour est le type de la valeur qui est retournée par la
méthode après son appel. Si la méthode ne fourni aucun
résultat, alors typeRetour est remplacé par le mot clé void.

ENSAM 2020-2021- T.HAJJI- 19


• Le mode de passage des paramètres dans les méthodes
dépend de la nature des paramètres :
– par référence pour les objets
– par copie pour les types primitifs

Exemple
class C {
void methode1(int i){
i+=12;
}
void methode2() {
int i = 3;
methode1(i);
System.out.println(i=" + i); // i=3
}
}
ENSAM 2020-2021- T.HAJJI- 20
IV. Création et manipulation d’Objets

Une fois la classe est définie, on peut créer des objets de la même
manière que la déclaration des types primitif:

Considérons la classe ClasseTest

class ClasseTest {
// corps de la classe ClasseTest
}

l’instruction:

ClasseTest a; // déclare a comme objet (variable) de type ClasseTest

ENSAM 2020-2021- T.HAJJI- 21


Attention:
- La déclaration d’une variable de type primitif réserve un
emplacement mémoire pour stocker la variable
- La déclaration d’un objet de type A, ne réserve pas une
place mémoire pour un objet de type A, mais seulement
un emplacement pour une référence à un objet de type A.
 les objets sont manipulés avec des références. Exemple
classique de la télécommande et la Télé.
Télé = objet
Télécommande = référence.

Objet
Référence
Télécommande Télé

ENSAM 2020-2021- T.HAJJI- 22


- Pour modifier l’objet (par exemple augmenter le
son, …) on utilise la référence (la télécommande).

- Avoir une référence ne veut pas dire avoir l’objet


(on peut avoir la télécommande sans avoir la télé).

ENSAM 2020-2021- T.HAJJI- 23


L’emplacement pour l’objet doit être demandé explicitement
dans le programme en faisant appel à l’opérateur new.
L’expression new NomClasse créée un emplacement pour un
objet de type NomClasse.

class NomClasse {
/* Corps de la classe */
}

NomClasse a = new NomClasse();

En générale:
1. Chaque objet met ses données membres dans sa propre zone
mémoire.
2. Les données membres ne sont partagées entre les objets.
ENSAM 2020-2021- T.HAJJI- 24
Exemple 1:
class UnTest {
float x;
int i;
boolean b;
}

UnTest data = new UnTest(); // créer un objet data

ENSAM 2020-2021- T.HAJJI- 25


Exemple 2:
Supposons qu’on veut avoir une chaîne de caractères alors
on crée une référence sur String:
String s;
Ici on a créé la référence mais pas l’objet. Pour créer
l’objet, il faut initialiser la référence s.
String s=new String ("cours Java");
ou
String s;
s = new String ("cours Java");

Ou tout simplement ( C’est un cas particulier en Java pour les


objets string) par:
String s= " cours Java "

ENSAM 2020-2021- T.HAJJI- 26


Accès aux données membres
Exemple 1:
class UnTest {
float x;
int i;
boolean b;
}
UnTest data = new UnTest(); // créer un objet data
Maintenant l’objet dont la référence data existe. Pour accéder à
une donnée membre on indique le nom de la référence à
l’objet suivi par un point, suivi par le nom du membre dans
l’objet de la manière suivante:
data.i=2; // affecte 2 au membre i
data.b=true; // affecte true au membre b
data.x=1.2f; // affecte 1.2 au membre x.
ENSAM 2020-2021- T.HAJJI- 27
Appels des méthodes
• Les méthodes ne peuvent être créer que comme des
composante d’une classe.
• Une méthode ne peut être appelée que pour un objet.
• L’appel d’une méthode pour un objet se réalise en
nommant l’objet suivi d’un point suivi du nom de la
méthode et de sa liste d’arguments:
nomObjet.nomMethode(arg1, ….).

nomObjet: nom de la référence à l’objet
nomMethode: nom de la méthode.

ENSAM 2020-2021- T.HAJJI- 28


Exemple: soit f () une méthode qui ne prend aucun paramètre
et qui retourne une valeur de type int.
Alors si on a une référence à un objet appelé a pour lequel f()
peut être appelée, on peut écrire: int x = a.f()

class UnTest {
float x;
int i;
boolean b;
int f() {
return 10;
}
}

UnTest a = new UnTest(); // créer un objet a;


int x = a.f(); // affecte à x la valeur retournée par f
ENSAM 2020-2021- T.HAJJI- 29
Cas particulier des types primitifs
Les types primitifs ont un traitement particulier:
1. on n’utilise pas new,
2. les variables (non les références) sont créées au moment de leurs
déclaration.

------------------------------------------------------------------------------
Type | Taille | Classe Wrapper |
--------- |--------------------------------|--------------------------------- |
boolean | | Boolean |
char | 16 bits, Unicode | Character |
byte | 8 bits | Byte |
short | 16 bits | Short |
int | 32 bits | Integer |
long | 64 bits | Long |
float | 32 bits IEEE 754 | Float |
double | 64 bits IEEE 754 | Double |
void | | Void |

ENSAM 2020-2021- T.HAJJI- 30


On peut traiter les type primitif comme des objet en
utilisant les classe wrapper qui leurs sont associées.

Exemple:
char c=‘x’; // type primitif directement déclaré
Character car = new Character(c); // classe wrapper
ou
Character car = new Character (‘x’);

ENSAM 2020-2021- T.HAJJI- 31


Remarque :
Quand une donnée d’un type primitif est membre d’une classe
on est assuré qu’elle a une valeur par défaut même si on ne
l’initialise pas:
----------------------------------------------------------------
Type primitifs | Valeur par défaut |
---------------------------- |-----------------------------------|
boolean | false |
char | ‘\u0000’ (null) |
byte | (byte)0 |
short | (short)0 |
int | 0 |
long | 0L |
float | 0.0f |
double | 0.0d |
-----------------------------------------------------------------

ENSAM 2020-2021- T.HAJJI- 32


Attention: Cette garanti d’initialisation par
défaut ne s’applique pas aux variables locales
(définition d’une fonction (méthode)).

ENSAM 2020-2021- T.HAJJI- 33


V. Notion de portée et de durée de vie des objets
Le concept de portée fixe simultanément la visibilité et la
durée de vie des noms définis dans cette portée. La portée
est fixée par les accolades { }.
Exemple:
{
int x=12; // seul x est accessible
{
int q=96; // x et q tous les deux sont accessibles
}
// seul x est accessible
// q est hors de portée
}
ENSAM 2020-2021- T.HAJJI- 34
Attention: Ceci n’est pas permis en Java
{
int x=12;
{
int x=96; // illégale en Java, valable en C, C++
}
}

ENSAM 2020-2021- T.HAJJI- 35


Portée des objet: Considérons une classe nommée A

{
A a=new A();
} // fin de portée

La référence a disparaît à la fin de la portée, par contre


l’objet qui été référencé par a existe toujours, mais on
n’a aucun contrôle sur lui (il reste inaccessible).
 Les objets n’ont pas la même durée de vie que les
types primitifs.

ENSAM 2020-2021- T.HAJJI- 36


Il n’existe aucun opérateur explicite pour détruire
l’objet dont on n’a pas besoin, mais il existe un
mécanisme de gestion automatique de la mémoire
connu sous le nom de ramasse miettes (en anglais
Garbage Collector). Son principe est le suivant:

- A tout instant on connaît le nombre de références à


un objet donné.
- Lorsqu’il n’existe plus aucune référence sur un objet,
on est certains que le programme ne peut pas y
accéder, donc l’objet devient candidat au ramasse
miette.
ENSAM 2020-2021- T.HAJJI- 37
VI. Champs de classe
Considérons la définition simpliste suivante:
class A {
int n;
float y;
}
Chaque objet de type A possède ses propres champs n et x. Par
exemple avec les déclarations
A a1=new A(), a2= new A();

a1.n et a2.n désignent deux champs différents.


a1.y et a2.y désignent aussi deux champs différents.

ENSAM 2020-2021- T.HAJJI- 38


On peut définir des champs qui n’existent qu’en un seul
exemplaire (ce qu’on nomme des champs de classe ou
champs statiques), en les déclarant avec l’attribut static. Par
exemple si nous définissons:
class A {
static int n;
float y;
}

A a1=new A(), a2=new A();


a1.n et a2.n désignent donc le même champs. Il est possible de
s’y référer en le nommant simplement

A.n // champs (statique) de la classe A

ENSAM 2020-2021- T.HAJJI- 39


VII. Quelques précisions
Identificateur:
• C’est une suite de caractères pour désigner les différentes
entités manipulés par un programme: variables, méthode,
classe, objet, …
• Il est formé de lettre et/ou de chiffres. Le premier caractère
est une lettre ou le caractère souligné (_).

Remarque:
- Tous les caractères sont significatifs.
- On fait la différence entre les majuscules et les minuscules.
- Mots clés: certains mots sont réservés par le langage et ne
peuvent pas être utilisés comme identificateur.

ENSAM 2020-2021- T.HAJJI- 40


Mise en page des programmes
La mise en page d’un programme Java est libre.
- Une instruction peut être étendue sur plusieurs lignes.
- Une ligne peut comporter plusieurs instructions

Emploi du code Unicode:


Java utilise le codage Unicode, qui est basé sur 2 octets (16 bits), par
conséquent on peut coder 65 536 symboles, ce qui permet de couvrir la
plus part des symboles utilisés dans le monde. Pour assurer la
portabilité, le compilateur commence par traduire le fichier source en
Unicode.

• On peut, par exemple, utiliser l’identificateur élément: int élément;


• On peut aussi utiliser le code Unicode d’un caractère (mais à éviter
pour la lisibilité) de la manière suivante: \uxxxx représente le caractère
ayant comme code Unicode la valeur xxxx.
Par exemple \u0041 représente le caractère A.

ENSAM 2020-2021- T.HAJJI- 41


Style de programmation non standard
- Mettre en Majuscule la première lettre des noms des classes.
Exemple:
class A () { //… }
- Si le nom de la classe est composée de plusieurs mots, ils
sont accolés (on ne les sépare pas par un trait bas) et la
première lettre de chaque mot est mise en majuscule.
Exemple:
class PremProg() { //…. }
- Pour le reste, méthodes, variables membres, noms des
références d’objets, le style retenu comme classe sauf que la
première lettre de l’identificateur est miniscule.

ENSAM 2020-2021- T.HAJJI- 42


Spécificateurs d’accès:
Il existe 3 mots clés pour spécifier l’accès au sein d’une classe:
public, private et protected.
• public: veut dire tout le monde
• private : veut dire que personne ne peut accéder à ces
définitions à part les méthodes interne de ce type.
• protected: se comporte comme private avec moins de
restriction. Une classe dérivée a un accès aux membres
protected mais pas aux membres private
• Accès par défaut, lorsqu’aucun de ces spécificateurs n’est
mentionné.

ENSAM 2020-2021- T.HAJJI- 43


Exemple:
class A {
public int x;
private int y;
public void initialise (int i, int j){
x=i;
y=j;
}
}
public class TestA{ // fichier source de nom TestA.java
public static void main (String args[]) {
A a;
a=new A(); // On peut aussi déclarer A a=new A();
a.initialise(1,3); // x vaut 1 et y vaut 3
a.x=2; // x vaut maintenant 2. On peut accéder à x car il est public
a.y=3; // ne compile pas car y est privée
}
}

ENSAM 2020-2021- T.HAJJI- 44


Ch. II. Les constructeurs

I. Introduction
Un objet a
– une adresse en mémoire (identifie l’objet)
– un comportement (ou interface)
– un état interne (les valeurs des variables)

• L’état interne est donné par des valeurs de variables


• Le comportement est donné par des fonctions ou
procédures, appelées méthodes

ENSAM 2020-2021- T.HAJJI- 45


Nous supposons qu’un objet de type Point est représenté par:

 Un état interne : deux coordonnées entières l’abscisse (x) et


l’ordonnée (y).
 Un Comportement: nous supposons que la classe dispose des
trois méthodes:
- initialise pour attribuer des valeurs aux coordonnées d’un
points
- déplace pour modifier les coordonnées d’un point
- affiche pour afficher les coordonnées d’un point

ENSAM 2020-2021- T.HAJJI- 46


public class Point{
private int x; // abscisse
private int y; // ordonnée

public void initialise (int abs,int ord){


x=abs;
y=ord;
}
public void deplace (int dx, int dy){
x+=dx;
y+=dy;
}
public void affiche (){
System.out.println(" abscisse : "+ x + " ordonnée : " + y);
}
}

ENSAM 2020-2021- T.HAJJI- 47


• Pour manipuler un objet, on déclare une référence sur la
classe de cet objet :
Exemple: Point a;
• Quand unPour créer un objet (instance de la classe),
on applique l'opérateur new.
Exemple: a = new Point();
• Une instance est créée,
- son état est conservé dans les variables d’instance
(son propre état interne)
- partage le code qui détermine son comportement
(les méthodes) avec les autres instances de la classe.
ENSAM 2020-2021- T.HAJJI- 48
Ainsi
a=new Point();
// créer un objet de type Point et place sa référence dans a.

Les objets interagissent en s’envoyant des messages: Les méthodes d’un


objet correspondent aux messages qu’on peut lui envoyer : quand un
objet reçoit un message, il exécute la méthode correspondante.

De manière générale on a:
objetQuiReçoitLeMessage.messageEnvoyé(paramètres);

Exemple des objets de type point:

a.initialise(1,1);
a.deplace(0,2);

ENSAM 2020-2021- T.HAJJI- 49


public class TstPoint{
public static void main (String args[]) {
Point a;
a=new Point();
a.initialise(1,1);
a.deplace(2,0);
Point b=new Point();
b.initialise(2,3);
b.affiche();
}
}

ENSAM 2020-2021- T.HAJJI- 50


Remarque:
- Pour chaque instance on appelle la méthode initialise pour
initialiser l’objet ainsi créer.
- Si on n’appelle pas la méthode initialise, l’objet de type Point
ainsi créer ne sera pas initialisé.
 Créer un objet, ne garanti pas son initialisation

ENSAM 2020-2021- T.HAJJI- 51


II. Définitions de Constructeur
On peut garantir l’initialisation d’un objet grâce à une
méthode spéciale appelée constructeur qui permet
d’automatiser le mécanisme d’initialisation d’un objet.

 Quand une classe possède un constructeur, Java l’appel


automatiquement à toute création d’objet avant qu’il ne
puisse être utilisé.

 La création et l’initialisation sont deux concepts unifiés

ENSAM 2020-2021- T.HAJJI- 52


• Chaque classe a un ou plusieurs constructeurs qui servent à
– créer les instances
– initialiser l’état de ces instances

• Un constructeur est une méthode qui:


– porte le même nom que la classe
– n’a pas de type retour
– peut disposer d’un nombre quelconque d’arguments
(éventuellement aucun).

Exemple:
Prenons l’exemple de la classe point et transformons la
méthode initialise en un constructeur en la nommant Point.

ENSAM 2020-2021- T.HAJJI- 53


public class Point{
private int x; // abscisse
private int y; // ordonnée
public Point (int abs, int ord) { // Constructeur, remplace initialise
x=abs;
y=ord;
}
public void deplace (int dx, int dy){
x+=dx;
y+=dy;
}
public void affiche (){
System.out.println(" abscisse : "+ x + " ordonnée : " + y);
}
}

ENSAM 2020-2021- T.HAJJI- 54


Les instructions:
Point a=new Point();
a.initialise(1,1)

Sont remplacées par


Point a = new Point(1,1); // crée l’instance et l’initialise

On peut aussi écrire:


Point a;
a=new Point(1,1);

Attention.
Dans la dernière version de la définition de la classe Point, l’instruction
Point a = new Point();
ne convient plus car le constructeur a besoin de deux arguments

ENSAM 2020-2021- T.HAJJI- 55


Un autre exemple
public class Etudiant {
private String nom, prenom; // Variables d’instance
private int codeNatEtudiant;
// Constructeur
public Etudiant(String n, String p) {
nom = n;
prenom = p;
}
public void setCNE (int cne) {
codeNatEtudiant = cne;
}
public static void main(String[] args) {
Etudiant e1;
e1 = new Etudiant("Mohammed", "Ali"); // création d'une instance de la classe Etudiant
e1.setCNE(23456765);
}
}

ENSAM 2020-2021- T.HAJJI- 56


III. Quelques règles concernant les constructeurs

1. Aucun type, même void, ne doit figurer devant son nom.

2. Lorsque le code d’une classe ne comporte pas de


constructeur, un constructeur par défaut sera
automatiquement ajouté par Java.
Dans ce cas on peut créer des instances (objets) de la classe
par des instructions telles que:

Point a=new Point(); //ok si Point n’a pas de constructeur


Etudiant e=new Etudiant(); //ok si Etudiant n’a pas de constructeur

ENSAM 2020-2021- T.HAJJI- 57


De manière générale:
Si pour une classe A donnée, l’instruction suivante est acceptée

A a=new A();
Cela signifie que:
- Soit A ne possède pas de constructeur
- Soit A possède un constructeur sans arguments.

ENSAM 2020-2021- T.HAJJI- 58


3.Un constructeur ne peut pas être appelé de la même manière que les
autres méthodes. Par exemple:

Point a=new Point(1,1); // ok car Point possède un constructeur

e1.Etudiant(("Mohammed", "Ali"); // Interdit car Etudiant possède


// un constructeur.

4. Un constructeur peut être déclaré private. Dans ce cas il ne pourra plus


être appelé de l’extérieur, c’est-à-dire il ne pourra pas être utiliser pour
instancier des objet. Exemple:
class A{
private A() { … } // constructeur privée sans arguments

}

A a=new A(); // erreur, le constructeur correspondant A() est privé
ENSAM 2020-2021- T.HAJJI- 59
Dans les exemples précédents, le constructeur initialise les
champs privés de l’objet.

Remarque: les champs d’un objet sont toujours initialisés par


défaut, contrairement à ce qui se passe pour les variables
locales, .

La création d’un objet entraîne toujours, par ordre chronologique,


les opérations suivantes:
- Initialisation par défaut de tous les champs de l’objet
- Une initialisation explicite lors de la déclaration du champ
- L’exécution des instructions du corps du constructeur

ENSAM 2020-2021- T.HAJJI- 60


Initialisation par défaut des champs d’un objet:
------------------------------------ |---------------------------------
Type du champ | Valeur par défaut
------------------------------------ |--------------------------------
boolean | false
char | caractère de code nul
int, byte, short, int long | 0
float, double | 0.f ou 0.
class | null
---------------------------------------------------------------------

ENSAM 2020-2021- T.HAJJI- 61


Initialisation explicite des champs d’un objet:
Une variable locale peut être initialiser lors de sa déclaration. Il
en va de même pour un champs. Considérons:

class A{
public A (…) {… } // Constructeur A

private int n=10;
private int p;
}

ENSAM 2020-2021- T.HAJJI- 62


L’instruction suivante
A objA=new A(…);

Entraîne successivement
- l’initialisation implicite des champs n et p de l’objet objA à 0
- L’initialisation (explicite) du champ n à la valeur figurant
dans sa déclaration, soit 10
- L’exécution des instruction du constructeur

ENSAM 2020-2021- T.HAJJI- 63


Appel du constructeur

Le corps du constructeur n’est exécuté qu’après


l’initialisation par défaut et l’initialisation explicite.

ENSAM 2020-2021- T.HAJJI- 64


class A {
public A() { // ici n vaut 20, p vaut 10 et np vaut 0
np=n*p;
n=5;
}
public void affiche(){
System.out.println("n="+n+" p="+p+" np= " + np)
}
private int n=20, p=10;
private int np;
}
public class Init {
public static void main (String args[]) {
A a=new A();
// ici a.n vaut 5, a.p vaut 10, mais a.np vaut 200
a.affiche();
}
}

Résultat de l’appel de la méthode affiche: n=5 p=10 np = 200

ENSAM 2020-2021- T.HAJJI- 65


IV. Surcharge des méthodes

On parle de surcharge (en anglais overload) lorsqu’un


même symbole possède plusieurs significations
différentes entre lesquelles on choisit en fonction du
contexte. Par exemple a+b, la signification du
symbole + dépend du type des variables a et b.

• En Java et C++, on peut surcharger une


méthode, c’est-à-dire, ajouter une méthode qui
a le même nom mais pas la même signature
qu’une autre méthode :
ENSAM 2020-2021- T.HAJJI- 66
Considérons l’exemple suivant ou la classe Etudiant est dotée
de 2 méthodes calcMoyenne:
- La première a deux arguments de ype float
- La deuxième a quatre arguments de type float

ENSAM 2020-2021- T.HAJJI- 67


class Etudiant {
private String nom, prenom; // Variables d’instance
private int codeNatEtudiant;
// Constructeur
public Etudiant(String n, String p) {
nom = n;
prenom = p;
}
public void setCNE (int cne) {
codeNatEtudiant = cne;
}

public float calcMoyenne(float m1, float m2) {


return (m1+m2)/2;
}
public float calcMoyenne(float m1, float m2, float m3, float m4) {
return (m1+m2+m3+m4)/4;
}
}

ENSAM 2020-2021- T.HAJJI- 68


public class TestEtudiant {
public static void main(String[] args) {
Etudiant e1;
e1 = new Etudiant("Mohammed", "Ali"); //
e1.setCNE(23456765);
System.out.println(“Moy1="+e1.calcMoyenne(10, 12));
System.out.println(“Moy2="+e1.calcMoyenne(10, 12, 8, 13));
}
}

ENSAM 2020-2021- T.HAJJI- 69


Considérons maintenant l’exemple suivant ou la classe Point
est dotée de 3 méthodes déplace:
- La première a deux arguments de type int
- La deuxième a un seul argument de type int
- La troisième a un seul argument de type short

ENSAM 2020-2021- T.HAJJI- 70


class Point {
public Point (int abs, int ord){ // Constructeur
x=abs; y=ord;
}
pubic void deplace (int dx, int dy) {
x+=dx; y+=dy;
}
pubic void deplace (int dx) {
x+=dx;
}
pubic void deplace (short dx) {
x+=dx;
}
private int x,y;
}
ENSAM 2020-2021- T.HAJJI- 71
public class Surdef1 {
public static void main(String arg[]) {
Point a=new Point(1,2);
a.deplace(1,3); // appel deplace (int,int)
a.deplace(2); // appel deplace (int)
short p=3;
a.deplace(p); // appel deplace (short)
byte b=2;
a.deplace(b); /* appel deplace(short) après
conversion de b en short */
}
}
ENSAM 2020-2021- T.HAJJI- 72
Il peut y avoir ambiguïté
Supposons que la classe Point est dotée des deux méthodes deplace
suivantes:
public void deplace(int dx, byte dy) {
x+=dx; y+=dy;
}
public void deplace(byte dx, int dy) {
x+=dx;
}
Considérons alors les instructions suivantes:
Point a =new Point(2,4)
int n; byte b;
a.deplace(n,b); // ok appel de deplace (int,byte)
a.deplace(b,n); // ok appel de deplace (byte,n)
a.deplace(b,b); // erreur, ambiguité

ENSAM 2020-2021- T.HAJJI- 73


• En Java, il est interdit de surcharger une méthode en
changeant le type de retour uniquement:
– c’est-à-dire ne différencier les 2 méthodes que par
leur type retour
Par exemple, one peut pas avoir les 2 méthodes
suivante dans une classe :
int moyenne(int, int); // division entière par 2
float moyenne(int,int); // moyenne réelle

ENSAM 2020-2021- T.HAJJI- 74


Surcharge des constructeurs (Plusieurs constructeurs)
En Java et C++, une classe peut avoir plusieurs constructeurs. Comme le nom
du constructeur est identique du nom de la classe, il ne peut y avoir qu’un seul
nom de constructeur. Par contre on peut avoir différentes initialisations.

class Etudiant {
private String nom, prenom; // Variables d’instance
private int codeNatEtudiant;
public Etudiant(String n, String p) { // Constructeur
nom = n;
prenom = p;
}
public Etudiant(String n, String p, int cne) {// Constructeur
nom = n;
prenom = p;
codeNatEtudiant = cne;
}
}

ENSAM 2020-2021- T.HAJJI- 75


public class TestEtudiant {
public static void main(String[] args) {
Etudiant e1, e2;
e1 = new Etudiant("Mohammed", "Ali");
e2 = new Etudiant("Ouardi", " fatima", 22564321);
}
}

ENSAM 2020-2021- T.HAJJI- 76


V. Autoréférences: emploi de this

Il se peut qu’au seine d’une méthode, on ait besoin de faire


référence à l’objet ayant appelé cette méthode.

class A {
….
public void f(….) {
…… // ici l’emploi de this désigne la référence à l’objet
// ayant appelé la méthode f
}
}

ENSAM 2020-2021- T.HAJJI- 77


Exemple 1:
class Point {
public Point (int abs, int ord){
x=abs; y=ord;
}

private int x, y;
}
Comme les identificateurs abs et ord sont des arguments
muets pour la méthode Point, alors on peut les noter x et y
qui n’ont rien avoir avec les champs private x et y. Dans
ce cas la classe Point peut s’écrire comme suit:
ENSAM 2020-2021- T.HAJJI- 78
class Point {
public Point (int x, int y){
this.x=x; //this.x permet d’accéder au champs x de l’objet courant
this.y=y; //this.y permet d’accéder au champs y de l’objet courant
}

private int x,y;
}

ENSAM 2020-2021- T.HAJJI- 79


Exemple 2:

class Etudiant {
private String nom, prenom;
public Etudiant(String nom, String prenom) {
this.nom = nom;
this.prenom = prenom;
}

ENSAM 2020-2021- T.HAJJI- 80


Exemple 3:
Deux objets de même classe Point coïncident si leurs
coordonnées sont identiques. On peut écrire la méthode coïncide
de la façon suivante:

pubic boolean coincide (Point pt) {


return ((pt.x==this.x) && (pt.y==this.y))
}

Point a=new Point(x1,y1);


Point b=new Point(x2,y2);

Les point a est b sont identiques si: a.coincide(b) est TRUE

ENSAM 2020-2021- T.HAJJI- 81


Utilisation du mot clé this dans un constructeurs
Il est possible, qu’au sein d’un constructeur, on peut
appeler un autre constructeur de la même classe.
Pour faire on fait appel au mot clé this qui est
utilisé cette fois comme nom de méthode.

Supposons que la classe Point admet deux


constructeurs. Un constructeur initialise à l’origine
(au point (0,0)) et un autre initialise à un point
quelconque.

ENSAM 2020-2021- T.HAJJI- 82


Version 1: La classe Point peut être définie de la façon suivante:
class Point {
public Point (int abs, int ord){
x=abs; y=ord;
}
public Point( ) {
x=0;
y=0;
}

private int x,y;
}
Point a = new Point (); // créer l’objet a et l’initialise à l’origine,
// au point (0,0).
Point b = new Point (2,3); // créer l’objet b et l’initialise au point (2,3).
ENSAM 2020-2021- T.HAJJI- 83
Version 2: la classe Point peut être définie de la façon suivante:

class Point {
public Point (int abs, int ord){
x=abs; y=ord;
}
public Point( ) {
this (0,0);
}

private int x,y;
}
Point a = new Point (); // créer l’objet a et l’initialise à l’origine,
// au point (0,0).
Point b = new Point (2,3); // créer l’objet b et l’initialise au point (2,3).
ENSAM 2020-2021- T.HAJJI- 84
public class feuille {
int i=0;
feuille increment () {
i++;
return this;
}
public static void main (String[] args ) {
feuille x=new feuille ();
System.out.println("ii = " + x.increment().increment().increment().i );
}
}

Sortie:
i= 3

ENSAM 2020-2021- T.HAJJI- 85


public class feuille {
int i=0;
feuille increment () {
i++;
return this;
}
void print () {
System.out.println(" i = " + i);
}
public static void main (String[] args ) {
feuille x=new feuille ();
x.increment().increment().increment().print( )
}
}

Sortie:
i= 3

ENSAM 2020-2021- T.HAJJI- 86


Ch. III. Généralités sur les structures lexicales de Java

Types de variables
• Les variables d’instances
– sont déclarées en dehors de toute méthode
– conservent l’état d’un objet, instance de la classe
– sont accessibles et partagées par toutes les méthodes de la classe
• Les variables locales
– sont déclarées à l’intérieur d’une méthode
– conservent une valeur utilisée pendant l’exécution de la méthode
– ne sont accessibles que dans le bloc dans lequel elles ont été
déclarées

ENSAM 2020-2021- T.HAJJI- 87


Identificateurs
Un identificateur Java est une chaîne de caractères de
longueur quelconque:
– Le premier caractère est une lettre Unicode
– Le reste de la chaîne peut contenir des lettres et/ou des
chiffres et/ou le caractère souligné « _ »
– Les minuscules et les majuscules sont différenciés

Un identificateur Java ne doit pas être un mot-clé ou les


constantes true, false ou null

ENSAM 2020-2021- T.HAJJI- 88


L’affectation

• L’affectation est réalisée au moyen de l’opérateur « = ».


Signifie prendre la valeur du coté droit et la copier du coté
gauche.
• La partie droite est une constante, une variable ou une
expression qui retourne une valeur. La partie gauche est une
variable.
variable = constante ou variable ou expression

ENSAM 2020-2021- T.HAJJI- 89


• Soient A et B de type primitif
A=B; signifie que le contenu de B est copié dans A.
Si ensuite on modifie le contenu de A, alors le contenu de B
ne sera pas modifié.

• Soient A est B deux objets,


A=B; signifie qu’on copie la référence de B dans A. (A et B
pointeront vers le même objet référencé par B).
Si ensuite le contenu de A ou de B sont modifiés alors le
contenu de A et de B sont modifiés.

ENSAM 2020-2021- T.HAJJI- 90


Exemple:
class A {
public int i;
}
public class TestAffectation {
public static void main(String[] args) {
A a=new A(); A b=new A();
a.i=6; b.i=11;
a=b; // a et b contiennent la même référence, on a: a.i=11
a.i=20; // b.i et a.i valent 20
b.i=13; // a.i et b.i valent 13.
}
}

ENSAM 2020-2021- T.HAJJI- 91


Types de données en Java

• 2 grands groupes de types de données sont manipulés par


Java:
– types primitifs
– objets (instances de classe)

ENSAM 2020-2021- T.HAJJI- 92


Types primitifs
• Boolean:
prend deux valeurs true ou false
• Nombres entiers :
byte: représenté sur 1 octet,
short: représenté sur 2 octets,
int : représenté sur 4 octets,
long : représenté sur 8 octets
• Nombres à virgule flottante :
float : représenté sur 4 octets),
double : représenté sur 8 octets
• Caractère (un seul caractère) :
char : codé sur 2 octet par le codage Unicode

ENSAM 2020-2021- T.HAJJI- 93


Nombres entiers

• byte : compris entre –128 et 127


• short : compris entre –32 768 et 32 767
• int : compris entre –2.147 483 648 et 2 147 483 647
• long : compris entre -923 372 036 854 775 808
et 923 372 036 854 775 807

ENSAM 2020-2021- T.HAJJI- 94


Constantes nombres

Une constante « entière »


- est de type int
- Si elle est suffixée par « L » alors elle est de type long
Exemple:
108 // constante de type int
89L // constante de type long
014 // 14 en octal (base 8)= 12 en décimal
0xA7 // A7 en hexadécimal (base 16) = 167 en décimal

ENSAM 2020-2021- T.HAJJI- 95


Types des résultats des calculs
avec des nombres entiers
• Tout calcul entre entiers donne un résultat de type int
• si au moins un des opérandes est de type long, alors le
résultat est de type long
Exemple
byte b1 = (byte)20;
byte b2 = (byte)15;
byte b3 = b1 + b2;
provoquera une erreur car b1 + b2 est de type int (codé sur
32 bits) alors que b3 est de type byte (codé sur 8 bits
seulement)
ENSAM 2020-2021- T.HAJJI- 96
Les nombres flottants
• float : environ 7 chiffres significatifs ;
– valeur absolue (arrondie) maximal 3,4 x 1038 ( constante prédéfinie
Float.MAX_VALUE)
– valeur absolue (arrondie) minimal 1,4 x 10-45 (constante prédéfinie
Float.MIN_VALUE)

• double : environ 15 chiffres significatifs ;


– valeur absolue maximal (arrondie) 1,8 x 10308 (constante prédéfinie
Double.MAX_VALUE)
– valeur absolue minimal (arrondie) 4,9 x 10-324 (constante prédéfinie
Double.MIN_VALUE)

ENSAM 2020-2021- T.HAJJI- 97


Constantes nombres
Une constante réelle est de type float si elle est suffixée
par « F » et de type double sinon

Exemple:
.567e2 // 5,67 de type double
5.123E-2F // 0,05123 type float

ENSAM 2020-2021- T.HAJJI- 98


Type caractère
• permet de manipuler des caractères: Java représente un caractère sur 2 octets
• Une variable de type caractère est déclaré par: char c1,c2;
• Constante de type caractère: ‘a’ , ‘E’

Les caractères disposant d’une notation spéciale.

Notation Code Unicode Abréviation usuelle Signification


\b 0008 BS(Back Space) Retour arrière
\t 0009 HT(Horizontal Tabulation) Tabulation horizontale
\n 000a LF(Line Feed) Saut de ligne
\f 000c FF(Form Feed) Saut de page
\r 000d CR(Cariage Return) Retour chariot
\" 0022
\’ 0027
\\ 005c

ENSAM 2020-2021- T.HAJJI- 99


Type booléen

Sert à représenter une valeur logique du type vrai/faux


Une variable de type booléen est déclaré par: boolean b;
b prend une des deux valeurs false ou true

ENSAM 2020-2021- T.HAJJI- 100


Constante null

• Référence inexistante (indique qu’une variable de


type non primitif ne référence rien) ; convient pour
tous les types non primitifs
– null

ENSAM 2020-2021- T.HAJJI- 101


Transtypage
• Java est un langage fortement typé
• Dans certains cas, il est nécessaire de forcer le
programme à considérer une expression comme étant
d’un type qui n’est pas son type réel ou déclaré
• On utilise pour cela le cast (transtypage) :
(type-forcé) expression
int x = 10, y = 3; double z;
z=x/y; // donne z=3.0; car x/y donne 3
// sin on veut que z=3.3333.. et pas 3.0
z = (double)x / y; // cast de x suffit

ENSAM 2020-2021- T.HAJJI- 102


Casts autorisés
• En Java, 2 seuls cas sont autorisés pour les casts :
– entre types primitifs,
– entre classes mère/ancêtre et classes filles.

ENSAM 2020-2021- T.HAJJI- 103


Casts entre types primitifs

• Un cast entre types primitifs peut occasionner une


perte de données :
conversion d'un int vers un short

• Un cast peut provoquer une simple perte de précision:


la conversion d'un long vers un float peut faire perdre
des chiffres significatifs mais pas l'ordre de grandeur

ENSAM 2020-2021- T.HAJJI- 104


Casts entre types primitifs

• Une affectation entre types primitifs peut utiliser un cast


implicite si elle ne provoque aucune perte

• De même, on peut affecter un entier à une variable de type


nombre à virgule flottante

• Sinon, elle doivent comporter un cast explicite

• L’oubli de ce cast explicite provoque une erreur à la


compilation

ENSAM 2020-2021- T.HAJJI- 105


Exemples de Casts
• short s = 1000000; // erreur !
• Cas particulier d’une affectation statique (repérable par le
compilateur) d’un int « petit » :
short s = 65; // pas d’erreur
• Pour une affectation non statique, le cast est obligatoire :
int i = 60;
short b = (short)(i + 5);
• Les casts de types « flottants » vers les types entiers tronquent
les nombres :
int i = (int)1.99; // i = 1, et pas 2

ENSAM 2020-2021- T.HAJJI- 106


Casts entre entiers et caractères
• Ils font correspondre un entier et un caractère qui a
comme code Unicode la valeur de l’entier
• La correspondance char → int, long s’obtient par
cast implicite
• Le code d’un char peut aller de 0 à 65.535 donc char
→ short, byte nécessite un cast explicite (short ne va
que jusqu’à 32.767)
• Les entiers sont signés et pas les char donc long, int,
short ou byte → char nécessite un cast explicite

ENSAM 2020-2021- T.HAJJI- 107


L’attribut final
L’attribut final indique que la valeur de la variable ne peut être
modifiée : on pourra lui donner une valeur une seule fois dans
le programme.

Variable d’instance final


• Une variable d’instance final est constante pour chaque objet.
Attention: elle peut avoir 2 valeurs différentes pour 2 objets
différents.
• Une variable d'instance final peut ne pas être initialisée à sa
déclaration mais elle doit avoir une valeur à la sortie de tous
les constructeurs

ENSAM 2020-2021- T.HAJJI- 108


Variable locale final
• Si la variable est d’un type primitif, sa valeur ne peut changer
• Si la variable référence un objet, elle ne pourra référencer un
autre objet mais l’état de l’objet pourra être modifié

final Etudiant e = new Etudiant("Mohammed", "Ali");


...
e.nom = "Ahmed"; // ok, changement de l’état e l’objet
e.setCNE(32211452); // ok, changement de l’état e l’objet
e = new Etudiant("Ahmed"); // Interdit, référence à un
// autre objet

ENSAM 2020-2021- T.HAJJI- 109


Instructions de contrôle

ENSAM 2020-2021- T.HAJJI- 110


Structure Alternative « if… else »
if (expressionBooléenne)
bloc-instructions ou instruction
else
bloc-instructions ou instruction

int x = y + 5;
if (x % 2 == 0) {
type = 0;
x++;
}
else
type = 1;

Un bloc serait préférable, même s’il n’y a qu’une seule instruction

ENSAM 2020-2021- T.HAJJI- 111


Expression conditionnelle
expressionBooléenne ? expression1 : expression2
Est équivalent
if (expressionBooléenne)
expression1;
else
expression2;

Exemple:
int y = (x % 2 == 0) ? x + 1 : x;
est équivalent à
int y;
if (x % 2 == 0)
y = x + 1;
else
y = x;
Parenthèses pas indispensables

ENSAM 2020-2021- T.HAJJI- 112


Distinction de cas suivant une valeur

switch(expression) {
case val1: instructions;
break; // Attention, sans break, les instructions du cas suivant
// sont exécutées !
...
case valn: instructions;
break;
default: instructions;
}
expression est de type char, byte, short, ou int, ou de type énumération
• S’il n’y a pas de clause default, rien n’est exécuté si expression ne
correspond à aucun case

ENSAM 2020-2021- T.HAJJI- 113


Exemple de switch
char lettre;
int nbVoyelles = 0, nbA = 0,
nbT = 0, nbAutre = 0;
...
switch (lettre) {
case 'a' : nbA++;
case 'e' : // pas d’instruction !
case 'i' : nbVoyelles++;
break;
case 't' : nbT++;
break;
default : nbAutre++;
}

ENSAM 2020-2021- T.HAJJI- 114


Répétitions « tant que »

while(expressionBooléenne)
bloc-instructions ou instruction

do bloc-instructions ou instruction
while(expressionBooléenne)

Le bloc d’instructions est exécuté au moins une fois

ENSAM 2020-2021- T.HAJJI- 115


Répétition for
for(init; test; incrément){
instructions;
}
est équivalent à
init;
while (test) {
instructions;
incrément
}
ENSAM 2020-2021- T.HAJJI- 116
Exemple de for

int somme = 0;
for (int i=0; i < n; i++) {
somme += tab[i];
}
System.out.println(somme);

ENSAM 2020-2021- T.HAJJI- 117


Instructions liées aux boucles
• break sort de la boucle et continue après la boucle
• continue passe à l’itération suivante
• break et continue peuvent être suivis d’un nom
d’étiquette qui désigne une boucle englobant la
boucle où elles se trouvent (une étiquette ne peut se
trouver que devant une boucle)

ENSAM 2020-2021- T.HAJJI- 118


Etiquette de boucles
boucleWhile: while (pasFini) {
...
for (int i=0; i < n; i++) {
...
if (t[i] < 0)
continue boucleWhile;
...
}
...
}
ENSAM 2020-2021- T.HAJJI- 119
Les tableaux
• En Java les tableaux sont considérés comme des
objets.
– les variables de type tableau contiennent des
références aux tableaux
– les tableaux sont créés par l’opérateur new
– ils ont une variable d’instance (final) pour
désigner taille du tableau:
final int length

ENSAM 2020-2021- T.HAJJI- 120


Déclaration et création des tableaux
• Déclaration : La taille n’est pas fixée à la déclaration
int[] tabNotes;
Ou
int tabNotes[]; // possible, mais non recommandé
Attention: En java il n'est pas possible de définir des tableaux de taille
statique à la déclaration.
int[10] tab; // ne compile pas

• Création : C’est pendant la création qu’il faut donner la taille du tableau


tabNotes = new int[5];
Remarques:
– Chaque élément du tableau reçoit la valeur par défaut du type de base
du tableau
– La taille ne pourra plus être modifiée par la suite
– Les éléments d’un tableau peuvent être d’un type primitif ou d’un type
objet
ENSAM 2020-2021- T.HAJJI- 121
Initialisation
On peut lier la déclaration, la création et l’initialisation d’un tableau;
Sa longueur est alors calculée automatiquement d’après le nombre de
valeurs données.

Attention : cette syntaxe n'est autorisée que dans la déclaration) :


int[] tab = {10, 3*6, 4};
Etudiant [] etudiantsSMI = {
new Etudiant("Mohammed", "Ali"),
new Etudiant("Fatima", "Zahra")
}

On peut affecter « en bloc » tous les éléments d'un tableau avec un


tableau anonyme
int[] t;
t = new int[] {1, 2, 3};

ENSAM 2020-2021- T.HAJJI- 122


Indices du tableau: Les indices du tableau commence à 0 et se
termine à tab.length - 1

Taille du tableau
int[] tab = {10, 3*6, 4};
tabNotes = new int[8];

int l1 = tab.length; // l1 = 3
int l2 = tabNots.length; // l2 = 8
int e = tabNotes[8];
/* La compilation produit le message suivant :
ArrayIndexOutOfBoundsException */

ENSAM 2020-2021- T.HAJJI- 123


Exemple de tableau de chaînes: Paramètres de la ligne de commande

class TestArguments {
public static void main(String[] args) {
for (int i=0; i < args.length; i++)
System.out.println(args[i]);
}
}
$javac TestArguments
$ java TestArguments arg1 arg2
affichera
• arg1
• arg2

ENSAM 2020-2021- T.HAJJI- 124


Tableaux d’objets
Les éléments d’un tableau peuvent être d’un type objet.
Attention: Il faut créer les objets avant de les utiliser. Considérons
l’exemple de la classe Etudiant.

Etudiants [] etudiantSMI = new Etudiant[100];


// Chaque élément du tableau contient une référence vers un objet de type Etudiant
etudiantSMI[0].setCNE(11225467);
// setCNE(int cne) est une méthode de la classe Etudiant.

etudianSMI[0].codeNatEtudiant = cne;
// Erreur: etudiantSMI[0] est objet de type Etudiant, donc il faut le créer avant de l’utiliser

Etudiant [] etudiantSMI = new Etudiant[100];


// Chaque élément du tableau est une référence à un objet de type Etudiant
etudiantSMI[0] = new Etudiant(); // Création de l’objet etudiantSMI[0]
etudiantSMI[0].setCNE(11225467);

ENSAM 2020-2021- T.HAJJI- 125


Affectation de Tableaux:
Java permet de manipuler globalement les tableaux par
affectation de leurs références

Soient t1 et t2 deux tableaux


t1=t2; // La référence contenue dans t2 est affectée à t1
Maintenant t1 et t2 désignent le même objet tableau qui était
initialement référencé par t2

t1[2]=3; // t2[2] vaut aussi 3 t2[2]=3.


t2[4]=6; // t1[4] vaut aussi 6 t1[4]=6;
Attention: Si on veut copier uniquement les valeurs de t2 dans
t1, alors dans ce cas on peut faire une copie élément par
élément

ENSAM 2020-2021- T.HAJJI- 126


Les tableaux en argument d’une méthode:

Le passage des tableaux comme paramètres des méthodes se


fait par référence (comme les objets) et non par copie
(comme les types primitifs)

La méthode agit directement sur le tableau et non sur sa copie

ENSAM 2020-2021- T.HAJJI- 127


Tableaux à plusieurs dimensions

• Déclaration

int[][] notes; // c’est un tableau de tableaux


Chaque élément du tableau contient une référence vers un
tableau

• Création: Il faut donner au moins les premières dimensions


notes = new int[30][3]; // Tableau de 30 étudiants, chacun
// des 30 étudiants a au plus 3 notes
notes = new int[30][]; // Chacun des 30 étudiants a un
// nombre de notes variable

ENSAM 2020-2021- T.HAJJI- 128


Déclaration, création et initialisation
int[][] notes = { {10, 11, 9}, // 3 notes
{15, 8}, // 2 notes
...
};
Affectation
• notes[10][2] = 12;

ENSAM 2020-2021- T.HAJJI- 129


Exemple
int[][] t;
t = new int[2][];
int[] t0 = {0, 1};
t[0]= t0; // t[0] est un tableau
t[1] = new int[] {2, 3, 4, 5}; // Déclaration et initialisation
for (int i = 0; i < t.length; i++) {
for (int j = 0; j < t[i][].length; j++) {
System.out.print(t[i][j] + "; ");
}
System.out.println();
}

ENSAM 2020-2021- T.HAJJI- 130


Ch. IV. Héritage
L'héritage est une notion fondamentale en Java et de
manière générale dans les langages de
programmation par Objets.

Il permet de créer des classes dérivées (classes qui


héritent) par combinaison de classes déjà existantes
(classes de base) sans toucher au code source de la
classe de base (on a seulement besoin du code
compilé de la classe de base).

ENSAM 2020-2021- T.HAJJI- 131


La classe dérivée:
– se comporte comme la classe de base mais avec
quelques différences.
– on a seulement besoin du code compilé de la
clase de base.

On peut par exemple:


– ajouter de nouvelles méthodes
– adapter (modifier) certaines méthodes

ENSAM 2020-2021- T.HAJJI- 132


Syntaxe:
class <ClasseDerivee> extends <ClasseDeBase>
Interprétation:
Permet de définir un lien d'héritage entre deux classes:
- La classe <ClasseDeBase> est le nom de la classe de base. Elle
s'appelle une classe mère, une classe parente ou une super-classe. Le
mot clef extends indique la classe mère :
- La classe <ClasseDerivee> est le nom de la classe dérivée. Elle hérite
de la classe <ClasseDeBase> . On l'appelle une classe fille ou une sous-
classe
Remarque:
- Par défaut il n’y a pas de extends dans la définition d’une classe: une
classe hérite de la classe Object
- Un objet de la classe dérivée ClassDerivee accède aux membres publics de
sa classe de base ClasseDeBase

ENSAM 2020-2021- T.HAJJI- 133


Exemple
class FormeGeometrique{ // classe mère
// Définition des attributs et des méthodes
}
class Point extends FormeGeometrique { // classe dérivée
// Définition de nouveaux attributs (propres à la classe Point)
// Définition de nouvelles méthodes (propres à la classe Point)
// Modification des méthodes qui sont déjà définies dans la classe mère
// Point hérite des méthodes et attributs de la superclasse
FormeGeometrique
}
class Cercle extends Point {
Définition de nouveaux attributs (propres à la classe Cercle)
// Définition de nouvelles méthodes (propres à la classe Cercle)
// Modification des méthodes qui sont déjà définies dans la classe mère
// Cercle hérite des méthodes et attributs de la superclasse Point
}
ENSAM 2020-2021- T.HAJJI- 134
Une instance (un objet) d’une classe dérivée peut faire
appelle (accès depuis l’extérieur)
- Aux méthodes et aux membres publics de la classe
dérivée
- Aux méthodes et membres publics de la classe de
base

De même (pour l’accès depuis l’intérieur)


- Une méthode d’une classe dérivée a accès aux
membres publics de sa classe de base
- Une méthode d’une classe dérivée n’a pas accès aux
membres privées de sa classe de base
ENSAM 2020-2021- T.HAJJI- 135
Quand on écrit la classe <ClasseDerivee> on doit seulement:
– écrire le code (variables ou méthodes) lié aux nouvelles
possibilités: offrir de nouveaux services.
– redéfinir certaines méthodes: enrichir les services rendus
par une classe.

ENSAM 2020-2021- T.HAJJI- 136


Lorsqu'une classe hérite d'une autre classe
 Elle bénéficie automatiquement des définitions des
attributs et des méthodes de la classe mère.
 Elle peut y ajouter ses propres définitions.
• ajouter des variables, des méthodes et des
constructeurs.
• redéfinir des méthodes: exactement le même
nom et la même signature.
• surcharger des méthodes: même nom mais pas
les mêmes arguments (signature).

ENSAM 2020-2021- T.HAJJI- 137


Remarques2:
- Java ne permet pas l’héritage multiple: chaque classe a
une et une seule classe mère dont elle hérite les
variables et les méthodes.
- C++ permet l’héritage multiple.

ENSAM 2020-2021- T.HAJJI- 138


Construction des classes dérivée
- Lorsqu'on construit une instance de ClasseDerivee, on obtient
un objet dont une partie est construite grâce à la définition de
ClasseDerivee et une partie grâce à la définition de la
super-classe ClasseDeBase.
- En Java, le constructeur de la classe drivée doit prendre en
charge l’intégralité de la construction de l’objet.
 Le constructeur de la classe dérivée doit faire appel au
constructeur de la classe de base en appelant explicitement
la méthode super() ainsi que la liste des paramètres
appropriés.
Remarque: l’appel du constructeur de la super classe (appel de
la méthode super()) doit être la première instruction dans la
définition du constructeur de la classe dérivée.
ENSAM 2020-2021- T.HAJJI- 139
Exemple 1:
class ClasseDeBase{
public ClasseDeBase(int i) { // constructeur de la classe de base
System.out.println(" Classe de Base: " + i);
}
}
class ClasseDerivee1 extends ClasseDeBase {
public ClasseDerivee1(int i, int j) { // constructeur de la classe dérivée 1
super(i+j); // appel du constructeur ClasseDeBase
System.out.println(" Classe dérivée1: " + i+ " , "+j);
}
}
class ClasseDerivee2 extends ClasseDerivee1{
public ClasseDerivee2(int i) { // constructeur de la classe dérivée 2
super(i,i); // appel du constructeur ClasseDerivee1
System.out.println(" Classe dérivée2: " + i);
}
}

ENSAM 2020-2021- T.HAJJI- 140


public class TestHeritage{
public static void main (String args[]) {
ClasseDerivee2 a=new ClasseDerivee2(7);
}
}

Sortie:
Classe de Base : 14
Classe dérivée1: 7 , 7
Classe dérivée2: 7

ENSAM 2020-2021- T.HAJJI- 141


Exemples des cas possibles:
Exemple 1:
class ClasseDeBase{
ClasseDeBase(arguments) {

}

}
class ClasseDerivee extends ClasseDeBase {
// Pas de constructeur
….
}
On obtient une erreur de compilation. Un constructeur de la classe dérivée
doit être défini est qui doit appeler le constructeur de la classe de base.

ENSAM 2020-2021- T.HAJJI- 142


Exemple2:
class ClasseDeBase{
ClasseDeBase(arguments) { // constructeur de la classe de base

}
}
class ClasseDerivee extends ClasseDeBase {
ClasseDerivee(arguments) { // constructeur de la classe de base
// l’appel de super () est obligatoire sinon une erreur
….
}
}

ENSAM 2020-2021- T.HAJJI- 143


Exemple 3:
class ClasseDeBase{
ClasseDeBase(arguments) { // constructeur de la classe de base

}
ClasseDeBase() { // constructeur sans paramètre de la classe de base

}
}
class ClasseDerivee extends ClasseDeBase {
ClasseDerivee(arguments) {// constructeur de la classe dérivée
// l’appel de super () n’est pas obligatoire.
// si super() n’est pas appelé explicitement,
// le constructeur par défaut de ClasseDeBase est appelé
….
}
}
ENSAM 2020-2021- T.HAJJI- 144
Exemple 4:
class ClasseDeBase{
// Pas de constructeur

}
class ClasseDerivee extends ClasseDeBase {
// Pas de constructeur
….
}

La création d’un objet de type ClasseDerivee entraîne l’appel


de constructeur par défaut qui appelle le constructeur par
défaut de la ClasseDeBase.

ENSAM 2020-2021- T.HAJJI- 145


Exemple pratique:
class ClasseDeBase{
ClasseDeBase() {
System.out.println(" Classe de Base: ");
}
}
class ClasseDerivee1 extends ClasseDeBase {
ClasseDerivee1() {
// Appel implicite du constructeur par défaut de ClasseDeBase
System.out.println(" Classe dérivée1: ");
}
}
class ClasseDerivee2 extends ClasseDerivee1{
ClasseDerivee2() {
// Appel implicite du constructeur par défaut de ClasseDerivee1
System.out.println(" Classe dérivée2: " );
}
}

ENSAM 2020-2021- T.HAJJI- 146


public class TestHeritage{
public static void main (String args[]) {
ClasseDerivee2 a=new ClasseDerivee2();
}
}

Sortie:
Classe de Base :
Classe dérivée1:
Classe dérivée2:

ENSAM 2020-2021- T.HAJJI- 147


Résumé:
Si on n'appelle pas le constructeur de la super-classe,
le constructeur par défaut est utilisé si:
- aucun constructeur n’est défini
- au moins un constructeur sans paramètre est
défini
sinon le compilateur déclare une erreur

ENSAM 2020-2021- T.HAJJI- 148


Notion de la Redéfinition

Ne pas confondre redéfinition et surcharge des


méthodes :
– on redéfinit une méthode quand une nouvelle
méthode a le même nom et la même signature
qu’une méthode héritée de la classe mère.
– on surcharge une méthode quand une nouvelle
méthode a le même nom, mais pas la même
signature, qu’une autre méthode de la même classe

ENSAM 2020-2021- T.HAJJI- 149


- Lorsqu'un attribut ou une méthode ont été définis dans une
classe et sont redéfinis dans une classe dérivée (qui en
hérite), les éléments visibles sont ceux redéfinis dans la
classe dérivée. Les éléments de la classe de base (héritée)
sont alors masqués.

class Rect extends ObjetGraphique {


void move(int dx, int dy);
...
}
class Cercle extends ObjetGraphique{
void move(int dx, int dy);
...
}

ENSAM 2020-2021- T.HAJJI- 150


- On peut avoir les mêmes méthodes move() dans
des classes héritant les unes des autres. Dans ce
cas, c'est la classe la plus dérivée de l'objet qui
détermine la méthode à exécuter, sans que le
programmeur ait à faire des tests sur le type de
l'objet à traiter.

ENSAM 2020-2021- T.HAJJI- 151


A* *: signifie la définition ou la
redéfinition d’une méthode f.

Class A: méthode de A
B Classe B: méthode de A
C* Classe D: méthode de D
Classe E: méthode de A
Classe C: méthode de C
Classe F: méthode de C
E
D* F

ENSAM 2020-2021- T.HAJJI- 152


- la redéfinition d'une méthode d'une classe consiste à fournir
dans une sous-classe une nouvelle implémentation de la
méthode. Cette nouvelle implémentation masque alors
complètement celle de la super-classe

- Grâce au mot-clé super, la méthode redéfinie dans la


sous-classe peut réutiliser du code écrit dans la méthode de la
super-classe, qui n'est plus visible autrement.

- super à un sens uniquement dans une méthode (comme le


mot-clé this).

ENSAM 2020-2021- T.HAJJI- 153


class Point {
public void afficher(){
System.out.pritln(" je suis en "+ x +" et " +y);
}
private int x,y;
}
class PointCol extends Point {
public void afficher() { // redéfinition de la méthode afficher
super.afficher(); // appel de la méthode afficher de la classe de base
System.out.println (" et ma couleur est: "+ couleur);
}
private byte couleur;
}

ENSAM 2020-2021- T.HAJJI- 154


Soit une classe B qui hérite d'une classe A. Soit f une
méthode définie dans A. Dans une méthode d'instance
g() de B, super. sert à désigner un membre de A.
par exemple: super.f() désigne la méthode f() de A

Attention: On ne peut remonter plus haut que la classe


mère pour récupérer une méthode redéfinie :
– pas de « super.super.»

ENSAM 2020-2021- T.HAJJI- 155


Exemple:
class A {
public void f(){
System.out.println("Je suis dans la classe de base A");
}
}
class B extends A {
public void g(){
super.f(); // désigne la méthode f() de la classe mère A
System.out.println("je suis aussi dans la class derivee B");
}
}
public class TestRedefinition {
public static void main (String args[]) {
B b = new B();
b.g();
}
}

ENSAM 2020-2021- T.HAJJI- 156


Héritage (Suite)

• Une Classe final ne peut pas avoir de classes filles


• La redéfinition d'une méthode public ne peut être
private
• Une méthode final ne peut pas être redéfinie

ENSAM 2020-2021- T.HAJJI- 157


Sous-type
Le type B est un sous-type de A si on peut affecter une
expression de type B dans une variable de type A.
Les type primitifs
- int est un sous type de float
- float est un sous type de double
- …
Les objets
Les sous-classes d’une classe A sont des sous types de A.
Dans ce cas on peut écrire:
A a = new B(…); // la variable a est de type A, alors que
// l’objet référencé par a est de type B.
A aa; B b=new B();
aa=b; // aa de type A, référence un objet de type B

ENSAM 2020-2021- T.HAJJI- 158


Définitions:
- La classe (ou le type) réelle de l’objet est la classe du
constructeur qui a créé l’objet
Exemple: Soit B une sous classe de A
A a = new B(…); // B est la classe (type) réelle de l’objet a

- Le type (la clase) déclaré de l’objet est le type qui est


donné au moment de la déclaration de la variable qui
référence l’objet.
Exemple: Soit B une sous classe de A
A a = new B(…); // A est le type déclaré de l’objet a

ENSAM 2020-2021- T.HAJJI- 159


Cas des tableaux
Soit B une classe qui hérite de la classe A, alors on peut écrire :
A[] tab = new B[5];
Attention: Dans tab[] il faut les valeurs de type réel et non
celles du type déclaré (c’est à dire des valeur de type B et non
de type A). Par exemple, si on a les instructions suivantes:
A[] tab = new B[5];
A a = new A();
tab[0] = a;
• Passe à la compilation mais provoquera une erreur à
l’exécution car tab[0] reçoit une valeur de type A et
non une valeur de type B

ENSAM 2020-2021- T.HAJJI- 160


Polymorphisme
Exemple introductif:
Considérons l’exemple suivant où B est une classe qui hérite de la classe A. Soient f() une méthode
qui reédinie dans B et g une méthode définie dans A. On suppose que

class A {
public void f(){
System.out.println("Methode f(): Classe de base A");
}
public void g(){
System.out.println("Methode g(): Classe de base A");
}
}
class B extends A {
public void f(){
System.out.println("Methode f(): Classe B derivee de A");
public void h(){
System.out.println("Methode h(): Classe B derivee de A");
}
}

ENSAM 2020-2021- T.HAJJI- 161


A a=new A(); B b = new B();
a.f(); // appelle la méthode définie dans A
a=b; // A a = new(B);
a.f(); // appelle la méthode définie dans B
a.g(); // appelle la méthode définie dans A
b.g(); // appelle la méthode définie dans A

Il faut noter que la même écriture a.f(); peut correspondre à des appels
différents de la méthode f(). Ceci est réalisé grâce au polymorphisme.

Le Polymorphisme veut dire que le même service peut avoir un


comportement différent suivant la classe dans laquelle il est utilisé.
C’est un concept fondamental de la programmation objet, indispensable
pour une utilisation efficace de l’héritage

ENSAM 2020-2021- T.HAJJI- 162


Attention c’est important:
Si on a:
B b = new B();
b.h(); // appelle la méthode h() définie dans B
A a=new B();
a.h(); // erreur à la compilation même si la classe réelle possède
// la méthode h(). En effet la classe déclarée (classe A)
// ne ossède pas la méthode h().

• En effet, en Java, dès la compilation on doit garantir l’existence de la


méthode appelée typage statique) : la classe déclarée de l’objet qui
reçoit le message (ici la classe A ou une de ces classes ancêtres
(polymorphisme)) doit posséder cette méthode ().

ENSAM 2020-2021- T.HAJJI- 163


• Le polymorphisme est obtenu grâce au mécanisme
de la liaison retardée (tardive) « late binding »: la
méthode qui sera exécutée est déterminée
– seulement à l’exécution, et pas dès la compilation
– par le type réel de l’objet qui reçoit le message (et pas
par son type déclaré)

ENSAM 2020-2021- T.HAJJI- 164


Mécanisme de la liaison retardée: cas des méthodes redéfinies
Soit D la classe réelle d’un objet d (D est la classe du constructeur qui a créé
l’objet d) et soit A la classe de déclaration de l’objet d (A d = new D();).
Si on a l’instruction: d.f();
quelle méthode f() sera appelée ?
1. Si la méthode f() n’est pas définie dans une classe ancêtre de la classe de
déclaration (classe A) alors erreur de compilation.
2. Si non
– Si la méthode f() est redéfinie dans la classe D, alors c’est cette
méthode qui sera exécutée
– Sinon, la recherche de la méthode f() se poursuit dans la classe mère de
D, puis dans la classe mère de cette classe mère, et ainsi de suite,
jusqu’à trouver la définition d’une méthode f() qui sera alors exécutée.

ENSAM 2020-2021- T.HAJJI- 165


La méthode appelée ne dépend que du type réel de l’objet et non du type
déclaré.

Soit B une classe qui hérite de la classe A, et soit f() une méthode définie
dans A et redéfinie dans B. Si on a:
A a = new B();
a.f();
Alors la méthode f() appelée est celle définie dans B.

• Si C hérite de B et si la méthode f() est redéfinie dans C, alors si on a:


A a = new C(); // Ok car C hérite de B qui hérite de A
a.f();
La méthode appelée est celle définie dans C.

ENSAM 2020-2021- T.HAJJI- 166


Utilités du Polymorphisme:
Le polymorphisme permet d’éviter les codes qui
comportent de nombreux embranchements et tests.

Exemple
Considérons une classe FormeGeometrique. Supposons
que les classes Rectangle et Cercle héritent de la super
classe FormeGeometrique. Dans un tableau hétérogène, on
ranges des objets de type Rectangle, Cercle. Ensuite on
affiche le contenu du tableau

ENSAM 2020-2021- T.HAJJI- 167


Exemple
class FormeGeometrique {
public void dessineRectangle() {} // méthode vide
public void dessineCercle() {} // méthode vide
}
class Rectangle extends FormeGeometrique {
public void dessineRectangle() {
System.out.println("Je suis un rectangle ");
}
}
class Cercle extends FormeGeometrique {
public void dessineCercle() {
System.out.println("Je suis un cercle .... ");
}
}

ENSAM 2020-2021- T.HAJJI- 168


public class TestFigPoly {
public static void main(String[] args) {
FormeGeometrique [] figures = new FormeGeometrique[3];
figures[0]=new Rectangle();
figures[1]=new Cercle();
figures[2]=new Cercle();
for (int i=0; i < figures.length; i++) {
if (figures[i] instanceof Rectangle)
figures[i].dessineRectangle();
else if (figures[i] instanceof Cercle)
figures[i].dessineCercle();
}
}
}
instanceof: Soit b est une instance d'une classe B alors (b instanceof A)
retourne true si B est une sous classe de A. En particulier (b instanceof
B) retourne true.
ENSAM 2020-2021- T.HAJJI- 169
Inconvénients dans le code précédent:
1. Si on veut rajouter une nouvelle forme géométrique par
exemple, triangle alors on est obliger de:
- changer dans le code source aux niveaux définition de la classe
(rajouter la méthode vide public void dessineTriangle() {})
- Rajouter un branchement pour la forme Triangle
2. Si on traite plusieurs formes géométrique, alors le code
comportera plusieurs tests.

En exploitant le polymorphisme, on peut améliorer le


code précédent
- Eviter les tests
- Rendre le code extensible: rajouter de nouvelles
sous-classes sans toucher au code existant)

ENSAM 2020-2021- T.HAJJI- 170


L’exemple peut être réécrit de la manière suivante en
exploitant le polymorphisme
class FormeGeometrique {
public void dessineFigure() {} // méthode vide
}
class Rectangle extends FormeGeometrique {
public void dessineFigure() {
System.out.println("Je suis un rectangle ");
}
}
class Cercle extends FormeGeometrique {
public void dessineFigure() {
System.out.println("Je suis un cercle .... ");
}
}

ENSAM 2020-2021- T.HAJJI- 171


public class TestFigPoly {
public static void main(String[] args) {
FormeGeometrique [] figures = new FormeGeometrique[3];
figures[0] = new Rectangle();
figures[1] = new Cercle();
figures[2] = new Cercle();
for (int i=0; i < figures.length; i++)
figures[i].dessineFigure();
// pas besoin de spécifier quelle forme
}
}

ENSAM 2020-2021- T.HAJJI- 172


Un autre exemple d’exploitation du Polymorphisme:
Considérons l’exemple précédent, en supposant que le
rectangle et le cercle sont caractérisés par des champs privés
qui désignent:
- La position dans le plan (position du centre)
- La longueur et la largeur pour le rectangle
- Le rayon pour le Cercle.

Considérons un tableau hétérogène qui contient des formes


géométriques différentes: rectangles, cercles, ...

Le but et d’afficher le type de la forme géométrique et ses


caractéristiques

ENSAM 2020-2021- T.HAJJI- 173


1ère solution:
class FormeFigure {
public void dessineFigure() {}
}

class Rectangle extends FormeFigure {


public Rectangle(int x, int y, int longueur, int largeur) { // centre (x,y)
this.x=x; this.y=y;
this.largeur=largeur; this.longueur=longueur;
}
public void dessineFigure() {
System.out.println(" Je suis un Rectangle de longueur " +longueur +" et de largeur " + largeur);
System.out.println(" ma position dans le plan est (" + x + " ," + y + ")" );
}
private int x,y;
private int largeur, longueur;
}

ENSAM 2020-2021- T.HAJJI- 174


class Cercle extends FormeFigure {
public Cercle(int x, int y, int rayon){ // centre (x,y)
this.x=x; this.y=y;
this.rayon=rayon;
}
public void dessineFigure(){
System.out.println(" Je suis un cercle de Rayon " + rayon);
System.out.println(" ma position dans le plan est (" + x + " ," + y + ")" );
}
private int x,y;
private int rayon;
}

ENSAM 2020-2021- T.HAJJI- 175


public class TestFigPolySuite {
public static void main(String[] args) {
FormeFigure [] figures = new FormeFigure[2];
figures[0]=new Rectangle(1,2,15,6);
figures[1]=new Cercle(0,0,4);
for (int i=0; i < figures.length; i++)
figures[i].dessineFigure();
}
}

ENSAM 2020-2021- T.HAJJI- 176


2ème solution : on ne redéfinie pas la position dans le plan qui est la même pour
toutes les formes géométrique.

class FormeFigure {
public FormeFigure(int x, int y) { // constructeur
this.x=x; this.y=y;
}
public void dessineFigure() {
afficheMonIdentite();
System.out.println(" ma position dans le plan est (" + x + " ," + y + ")" );
}
public void afficheMonIdentite(){}; // méthode vide
private int x,y;
}

ENSAM 2020-2021- T.HAJJI- 177


class Rectangle extends FormeFigure {
public Rectangle(int x, int y, int longueur, int largeur) { // centre (x,y)
super(x,y);
this.largeur=largeur; this.longueur=longueur;
}
public void afficheMonIdentite() {
System.out.println(" Je suis un Rectangle de longueur " +longueur +" et de largeur " + largeur);
}
private int largeur, int longueur;
}
class Cercle extends FormeFigure {
public Cercle(int x, int y, int rayon){ // centre (x,y)
super(x,y);
this.rayon=rayon;
}
public void afficheMonIdentite() {
System.out.println(" Je suis un cercle de Rayon " + rayon);
}
private int rayon;
}
ENSAM 2020-2021- T.HAJJI- 178
public class TestFigPolySuite {
public static void main(String[] args) {
FormeFigure [] figures = new FormeFigure[2];
figures[0]=new Rectangle(1,2,15,6);
figures[1]=new Cercle(0,0,4);
for (int i=0; i < figures.length; i++)
figures[i].dessineFigure();
// la méthode afficheMonIdentite() appelée est celle définie dans la classe
//réelle de l’objet et non celle définie dans la classe de déclaration
}
}

ENSAM 2020-2021- T.HAJJI- 179


Cast (transtypage): conversions de classes
• Le « cast » est le fait de forcer le compilateur à
considérer un objet comme étant d’un type qui n’est
pas le type déclaré ou réel de l’objet

• En Java, les seuls casts autorisés entre classes sont les


casts entre classe mère et classes filles

ENSAM 2020-2021- T.HAJJI- 180


Syntaxe
• Pour caster un objet en classe A :
(C) o;

• Exemple :
FormeFigure a = new FormeFigure();
Rectangle r = (Rectangle) a;
FormeFigure b;
(Rectangle) b = r;

ENSAM 2020-2021- T.HAJJI- 181


UpCast : classe fille → classe mère

• Upcast : un objet est considéré comme une instance


d’une des classes ancêtres de sa classe réelle
• Il est toujours possible de faire un upcast car tout
objet peut être considéré comme une instance d’une
classe ancêtre
• Le upcast est souvent implicite

ENSAM 2020-2021- T.HAJJI- 182


DownCast : classe mère → classe fille

• Downcast : un objet est considéré comme étant d’une


classe fille de sa classe de déclaration
• Toujours accepté par le compilateur
• Mais peut provoquer une erreur à l’exécution ; à
l’exécution il sera vérifié que l’objet est bien de la
classe fille
• Un downcast doit toujours être explicite

ENSAM 2020-2021- T.HAJJI- 183


Classes abstraites

Une classe abstraite (abstract class) est une classe déclarée


avec le mot clé abstract class.
Par exemple:
abstract class A {

}

Dans une classe abstraite on peut trouver: des champs, des


méthodes et des méthodes abstraites

ENSAM 2020-2021- T.HAJJI- 184


• Une méthode est abstraite, lorsqu’on la déclare sans
donner son implémentation: on ne fournit que le type
de la valeur de retour et la signature (l’entête de la
méthode).
• Les méthodes abstraite sont déclarée avec le mot clè
abstract.
• Exemple:
abstract void f(int i, float x);
abstract double g();

• La méthode peut être implémentée par les classes


filles.
ENSAM 2020-2021- T.HAJJI- 185
- On peut créer une référence sur un objet de type A (une
classe abstraite) mais il est interdit de créer une instance (un
objet) d’une classe abstraite
A a; // autorisé
A a = new A(); // n’est pas autorisé.
- Si B hérite de A alors on peut écrire:
A a = new B();
- Une méthode static ne peut être abstraite (car on ne peut
redéfinir une méthode static)
- Une classe qui contient au moins une méthode abstraite est
automatiquement abstraite
- Une méthode déclarée abstraite doit obligatoirement être
déclarée public.

ENSAM 2020-2021- T.HAJJI- 186


Intérêt des classe abstraites:

– la classe mère définit la structure globale d’un algorithme


– elle laisse aux classes filles le soin de définir des points
bien précis de l’algorithme.

ENSAM 2020-2021- T.HAJJI- 187


Interfaces

Définition des interfaces


• Une classe est purement abstraite si toutes ses
méthodes sont abstraites.
• Une interface est une « classe » purement abstraite
déclarée avec le mot clé interface, dont toutes les
méthodes sont publiques.

• Une interface est une liste de noms de méthodes


publiques.

ENSAM 2020-2021- T.HAJJI- 188


Exemples d’interfaces
public interface Figure {
public abstract void dessineFigure();
public abstract void deplaceFigure(int dx, int dy);
}

Les interfaces sont implémentées par des classes


• Une classe implémente une interface I si elle déclare «
implements I » dans son en-tête

ENSAM 2020-2021- T.HAJJI- 189


Ch. V La gestion des Exceptions
Définition

• Une exception est un signal indiquant que quelque chose


d’exceptionnelle (comme une erreur) s’est produit.
• Elle interrompt le flot d’exécution normal du programme

• Plutôt que de compliquer le code du traitement normal, on


traite les conditions anormales à part

• Le traitement « normal » apparaît ainsi plus simple et plus


lisible

ENSAM 2020-2021- T.HAJJI- 190


Exemple:
Considérons la classe point qui a un constructeur à
deux arguments (position du oint dans le plan) et
une méthode deplace qui permet de déplacer le
point dans le plan. Le programme doit s’arrêter si
au moins une des coordonnées du point est négatif.

ENSAM 2020-2021- T.HAJJI- 191


public class Point {
private int x, y;
public Point(int x, int y) {
if ((x < 0) || (y < 0)) { // Détection de l’Exception
System.out.println("Erreur de Construction"); // traitement de l’exception
System.exit(-1);
}
else {
this.x = x ; this.y = y; // traitement normal
}
}
public void deplace(int dx, int dy) {
if ((x+dx < 0) || (y+dy < 0)) { // Détection de l’ Exception
System.out.println("Mauvais Déplacement"); // traitement de l’exception
System.exit(-1);
}
else {
x = x+dx ; y = y+dy; // traitement normal
}
}
}

ENSAM 2020-2021- T.HAJJI- 192


Un 1er test
public class TestException {
public static void main(String[] argv) {
private int i=3;
// début du bloc susceptible de générer une exception
Point a = new Point(6,1);
a.deplace(-1,2);
a = new Point(3, 4);
a.deplace(3,-2);
// Fin du bloc susceptible de générer une exception
System.out.println (" Exécution bien passée i= "+i);
}
}
Sortie du programme:
Exécution bien passée i=3

Les appels de Point(6,1), deplace(-1, 2) , Point(3,4) et deplace(3,-2) n’ont généré


aucune exception..

ENSAM 2020-2021- T.HAJJI- 193


Un 2ème test
public class TestException {
public static void main(String[] argv) {
private int i=3;
// début du bloc susceptible de générer une exception
Point a = new Point(6,1);
a.deplace(-1,2);
a = new Point(-2, 4);
a.deplace(3,-6);
// Fin du bloc susceptible de générer une exception
System.out.println (" Exécution bien passée i= "+i);
}
}
Sortie du programme:
Erreur de Construction

Les appels de Point(6,1) et deplace(-1, 2) n’ont pas généré d’exception, donc ils sont
exécutés normalement. Par contre l’appel de Point(-2,4) a généré une exception et
a provoqué l’arrêt du programme (appel de System.exit(-1);). L’appel de
deplace(3,-6) et l’instruction System.out.printl() n’ont pas été exécutés.

ENSAM 2020-2021- T.HAJJI- 194


Dans cet exemple le traitement normal, la détection de
l’exception et son traitement ne sont pas séparés.

Java permet de séparer la détection de l’exception et de son


traitement.
Le traitement normal et le traitement des exceptions sont
dissociés.
– Plutôt que de compliquer le code du traitement normal, on traite
les conditions anormales à part
– Le traitement « normal » apparaît ainsi plus simple et plus lisible
– Le traitement des exceptions (erreurs) s’effectue dans une zone du
programme spéciale (bloc « catch »)

ENSAM 2020-2021- T.HAJJI- 195


Pratiquement:
Le code dans lequel une exception peut se produire est mis dans un bloc try, c’est-à-
dire on délimite un ensemble d’instructions susceptibles de déclencher une exception
par des blocs try {…}

try {
/* code */
}

La gestion des exceptions est obtenue par des blocs catch, où un bloc catch est associé à
une exception donnée.
Attention: Le bloc catch doit être juste après le bloc try, sinon erreur de compilation.
catch ( Type1Exception e) { // de type Type1Exception qui hérite de Exception
/* code */
}
catch ( Type2Exception e) { // de type Type2Exception qui hérite de Exception
/* code */
}
…..

ENSAM 2020-2021- T.HAJJI- 196


Lorsqu’une exception se produit dans le bloc try, alors :
– un saut est effectué vers un bloc (s) catch
– les blocs catch sont vérifiés un après l ’autre jusqu ’à ce
qu’on trouve un bloc correspondant à l ’exception
– le code du bloc catch est exécuté

ENSAM 2020-2021- T.HAJJI- 197


Exemple1:
Un 1er Test
public class Test {
public static void main(String[] argv) {
try {
Point a = new Point(6, 1);
a = new Point(-2, 4);
}
catch (ErrConst e) { // Erreur de type ErrConst qui hérite de Exception
System.out.println("Erreur de Construction");
System.exit(-1);
}
System.out.println(" Excution bien passée");
}
}
Sortie du programme:
Erreur de Construction

L’appel de Point(-2,4); génère une exception, donc un saut est effectué vers le bloc catch().
L’exécution du code du bloc catch() a provoqué l’arrêt du programme (appel de System.exit(-1);),
par conséquent l’appel de deplace(3,-6) et les instructions a près le bloc try n’ont pas été exécutés.

ENSAM 2020-2021- T.HAJJI- 198


Exemple1:
Un 2ème Test
public class Test {
public static void main(String[] argv) {
try {
Point a = new Point(6, 1);
a = new Point(2, 4);
}
catch (ErrConst e) { // Erreur de type ErrConst qui hérite de Exception
System.out.println("Erreur de Construction");
System.exit(-1);
}
System.out.println(" Exécution bien passée");
}
}
Sortie du programme:
Exécution bien passée

L’appel de Point(6,1) et Point(2,4) n’ont pas généré d’exception donc le code catch()
n’a pas été exécuté par conséquent l’exécution est allée au-delà du bloc try.

ENSAM 2020-2021- T.HAJJI- 199


Exemple2:
public class Test {
public static void main(String[] argv) {
try { Point a = new Point(1,4);
a.deplace(-3,1);
a = new Point(7, 4);
}
catch (ErrConst e) {
System.out.println("Erreur Construction");
System.exit(-1);
}
catch (ErrDepl ed) {
System.out.println("Erreur de Déplacement");
System.exit(-1);
}
}
}
Sortie du programme: Erreur de Déplacement

L’appel de deplace(-3,1) a généré une exception, donc un saut est effectué vers le bloc
catch(ErrDepl). L’exécution du code du bloc catch(ErrDepl) a provoqué l’arrêt du programme
(appel de System.exit(-1);).

ENSAM 2020-2021- T.HAJJI- 200


Comment lancer (déclencher) une exception
Une méthode déclare qu’elle peut lancer une exception par le mot clé
throws
Par exemple:
public void deplace(int dx, int dy) throws ErrDepl {
// Déclare que la méthode depalce() peut générer une exception
...
}
Ensuite la méthode lance une exception, en créant une nouvelle valeur
(un objet) d’exception en utilisant le mot clé throw

public void deplace (int dx, int dy) throws ErrDepl {


if ((x+dx <0) || (y+dy<0)) throw new ErrDepl();
// Détection de l’exception et Création d’une nouvelle valeur d’exception
x = x+dx ; y = y+dy; // traitement normal
}

ENSAM 2020-2021- T.HAJJI- 201


ErrDepl et ErrConst sont deux classes qui hérite de la classe
Exception. Elles peuvent être définie de la manière suivante:

class ErrDepl extends Exception{


}
class ErrConst extends Exception{
}

ENSAM 2020-2021- T.HAJJI- 202


Un Premier exemple complet:
class ErrConst extends Exception {}
class Point { private int x, y;
public Point(int x, int y) throws ErrConst {
if ((x < 0) || (y < 0)) throw new ErrConst(); // déclenche une exception
this.x = x ; this.y = y; // traitement normal
}
}
public class Test {
public static void main(String[] argv) {
try {
Point a = new Point(6, 1);
a = new Point(-2, 4);
}
catch (ErrConst e) { // Erreur de type ErrConst qui hérite de Exception
System.out.println("Erreur de Construction");
System.exit(-1);
}
}
}
ENSAM 2020-2021- T.HAJJI- 203
Un Deuxième exemple complet:
class ErrConst extends Exception {}
class ErrDepl extends Exception {}

public class Point {


private int x, y;
public Point(int x, int y) throws ErrConst {
if ((x < 0) || (y < 0)) throw new ErrConst();
this.x = x ; this.y = y;
}
public void deplace(int dx, int dy) throws ErrDepl{
if ((x+dx < 0) || (y+dy < 0)) throw new ErrConst();
x = x+dx ; y = y+dy;
}
}

ENSAM 2020-2021- T.HAJJI- 204


public class Test {
public static void main(String[] argv) {
try {
Point a = new Point(1,4);
a.deplace(0,1);
a = new Point(7, 4);
a.deplace(3,-5);
a.deplace(-1,-5);
}
catch (ErrConst e) {
System.out.println("Erreur de Construction");
System.exit(-1);
}
catch (ErrDepl ed) {
System.out.println("Erreur de Déplacement");
System.exit(-1);
}
}
}

ENSAM 2020-2021- T.HAJJI- 205


Les classes d’erreurs/exceptions

• La classe java.lang.Throwable (classe fille de Object) est


la superclasse de toutes les erreurs et exceptions rencontrées
dans le langage de programation Java.

• Java.lang est un package qui rassemble les classes de base


de Java. Toutes les classes et interfaces de java.lang sont
automatiquement importées par le compilateur.

ENSAM 2020-2021- T.HAJJI- 206


Arbre d’héritage des exceptions

Throwable

Error
Exception

RuntimeException Exceptions contrôlées

ENSAM 2020-2021- T.HAJJI- 207


Quelques sous-classes de RuntimeException (Exceptions
non contrôlées par le compilateur)

• NullPointerException: Tentative d'utiliser une référence null


• ClassCastException : Tentative de cast d'un objet dans un type
incorrecte.
• IndexOutOfBoundsException : Un indice (sur un tableau, une chaîne)
ou un intervalle défini par deux indices ont dépassé les limites
inférieures ou supérieures. Ses sous-classes :
– ArrayIndexOutOfBoundsException, pour les tableaux (indice
négatif ou supérieur ou égal à la taille du tableau).
– StringIndexOutOfBoundsException, pour les chaînes de
caractères.

ENSAM 2020-2021- T.HAJJI- 208


• ArrayStoreException : Tentative de stocker dans un tableau un
élément qui n'est pas du type des éléments du tableau ou castable dans
ce type.
• ArithmeticException: Une exception est survenue sur une opération
arithmétique, comme une division d'un entier par zéro. )
• NegativeArraySizeException : Tentative de créer un tableau ou une
chaîne avec une taille négative.
• IllegalArgumentException : Une méthode a été appelée avec un
mauvais argument ou invoquée sur un mauvais objet. Sa sous-classe
NumberFormatException
– NumberFormatException : Tentative de convertir dans un type
numérique une chaîne de caractères mal formatée.

ENSAM 2020-2021- T.HAJJI- 209


Constructeurs des exceptions

La création d'exception personnalisée peut être réalisée en rajoutant des constructeurs et


des membres supplémentaires. Par convention, toutes les exceptions doivent avoir au
moins 2 constructeurs :
– un sans paramètre
– un autre dont le paramètre est une chaîne de caractères utilisée pour décrire le
problème

Méthodes de la classe Throwable


• getMessage() retourne le message d’erreur décrivant l’exception
• printStackTrace() affiche sur la sortie standard la liste des appels de méthodes ayant
conduit à l’exception
• Exception(): constructeur sans argument
• Exception(String): Constructeur avec Argument

ENSAM 2020-2021- T.HAJJI- 210


Un premier exemple: définir un constructeur personnalisé qui a pour
argument une chaîne de caractères:

class ErrConst extends Exception {


public ErrConst() {}

public ErrConst(String msg) {


super(msg);
}
}
class Point {
private int x, y;
public Point(int x, int y) throws ErrConst {
if ((x < 0) || (y < 0)) throw new ErrConst(" Erreur aux points x=" +x+" et y=" +y);
this.x = x ; this.y = y;
}
}
ENSAM 2020-2021- T.HAJJI- 211
public class Test {
public static void main(String[] argv) {
try {
Point a = new Point(6, 1);
a = new Point(-2, 4);
}
catch (ErrConst e) {
System.out.println(e.getMessage);
System.exit(-1);
}
}
}

Sortie:
Erreur au point x= -2 et y=4

ENSAM 2020-2021- T.HAJJI- 212


Un deuxième exemple: définir un constructeur personnalisé qui a 2
arguments de type int :

class ErrConst extends Exception {


private int x, y;

public ErrConst(int x, int y) {


this.x=x; this.y=y;
}
public int getX() { return x;}
public int getY() { return y;}
}
class Point {
private int x, y;
public Point(int x, int y) throws ErrConst {
if ((x < 0) || (y < 0)) throw new ErrConst(x,y);
this.x = x ; this.y = y;
}
}
ENSAM 2020-2021- T.HAJJI- 213
public class Test {
public static void main(String[] argv) {
try {
Point a = new Point(6, 1);
a = new Point(-2, 4);
}
catch (ErrConst e) {
System.out.println(" Erreur aux points" +e.getX()+" et " +e.getY());
System.exit(-1);
}
}
}

Sortie:
Erreur aux points -2 et 4

ENSAM 2020-2021- T.HAJJI- 214


Méthode printStackTrace():

class ErrConst extends Exception{}


class Point {
private int x, y;
public Point(int x, int y) throws ErrConst {
if ((x < 0) || (y < 0)) throw new ErrConst();
this.x = x ; this.y = y;
}
}

ENSAM 2020-2021- T.HAJJI- 215


public class ExceptionTestStack {
public static void main(String[] argv) {
try {
Point a = new Point(6, 1);
a = new Point(-2, 4);
}
catch (ErrConst e) { // Erreur de type ErrConst qui hérite de Exception
System.out.println("Erreur de Construction");
e.printStackTrace();
System.exit(-1);
}
}
}
Sortie du Programme:

Erreur de Construction
ErrConst
at Point.<init>(ExceptionTestStack.java:5)
at ExceptionTestStack.main(ExceptionTestStack.java:14)

ENSAM 2020-2021- T.HAJJI- 216


Bloc finally
• C’est une instruction optionnelle qui est exécutée quelle que soit le
résultat du bloc try (c’est à dire qu’il ait déclenché ou non une exception)
• Il permet de spécifier du code dont l’exécution est garantie quoi qu’il
arrive.
try {
...
}
catch (…) {
...
}
finally {
...
}

ENSAM 2020-2021- T.HAJJI- 217


Exemple:
public class ExceptionTestStack {
public static void main(String[] argv) {
try {
Point a = new Point(6, 1);
a = new Point(-2, 4);
}
catch (ErrConst e) { // Erreur de type ErrConst qui hérite de Exception
System.out.println("Erreur de Construction");
e.printStackTrace();
}
finally {
System.out.println("Fin du Programme");
System.exit(-1);
}
}
}
Dans toutes les exécutions (déclenchement ou non d’exception), les instructions du
bloc finally seront exécutées.

ENSAM 2020-2021- T.HAJJI- 218


Ch. VI Complément
I. Interface
Classe qui implémente partiellement une interface
• Soit une interface I1 et une classe C qui l’implémente :
public class C implements I1 { … }
• C peut ne pas implémenter toutes les méthodes de I1
• Mais dans ce cas C doit être déclarée abstract (il lui
manque des implémentations)
• Les méthodes manquantes seront implémentées par les
classes filles de C

ENSAM 2020-2021- T.HAJJI- 219


• Implémentation de plusieurs interfaces
• Une classe peut implémenter une ou plusieurs
interfaces (et hériter d'une classe…) :
public class CercleColore extends Cercle
implements Figure, Coloriable {

ENSAM 2020-2021- T.HAJJI- 220


II. Champs de classe
Certaines variables sont partagées par toutes les
instances d’une classe. Ce sont les variables de
classe (modificateur static)
- Si une variable de classe est initialisée dans sa
déclaration, cette initialisation est exécutée une
seule fois quand la classe est chargée en mémoire

ENSAM 2020-2021- T.HAJJI- 221


Exemple
class A {
static int n;
float y;
}
A a1=new A(), a2=new A();

a1 et a2 deux instances différentes mais qui partagent la même variable n


a1.n et a2.n désignent donc le même champs. Il est possible de s’y
référer en le nommant simplement

a1.n=5; // automatiquement on a : a2.n =5


On peut écrire
A.n=5; // champs (statique) de la classe A, dans ce cas a1.n=5 et a2.n=5

ENSAM 2020-2021- T.HAJJI- 222


Exemple:

public class Etudiant {


private String nom, prenom;
private static int nbEtudiants = 0;
public Etudiant(String n, String p) {
nom = n;
prenom = p;
nbEtudiants++; // à chaque création d’un nouveau étudiant, le
// nombre d’étudiant augment de 1.
}
...
}

ENSAM 2020-2021- T.HAJJI- 223


III. Méthodes de classe
 Ce sont des méthodes qui ont un rôle indépendant d’un objet
spécifique. Elles exécutent une action indépendante d’une
instance particulière de la classe

 La déclaration d’une méthode de classe se fait à l’aide du


mot clé static.

 L’appelle d’une telle méthode ne nécessite que le nom de la


classe correspondante.

 Une méthode de classe ne pourra pas accéder à des champs


usuels (champs non statiques).

ENSAM 2020-2021- T.HAJJI- 224


Exemple

class A {

private float x; // champs usuel
static int n; // champs de classe
public static void f() { // méthode de clase
… //ici, on ne pas accéder au champs x, champs usuel
… // ici on peut accéder au champs n
}
}

ENSAM 2020-2021- T.HAJJI- 225


class Etudiant {
private String nom, prenom;
private static int nbEtudiants;
public Etudiant(String nom, String Prenom){
this.nom=nom;
this.prenom=prenom;
nbEtudiants++;
}
public static int getNbEtudiants(){
return nbEtudiants;
}
}

ENSAM 2020-2021- T.HAJJI- 226


public class MethodeStatic{
public static void main(String[] argv) {
Etudiant e1= new Etudiant("Mohammed","Ali");
Etudiant e2 =new Etudiant("Fatima","Zahra");

// les trois instructions suivante font la même chose

System.out.println("Nb etudiants = "+Etudiant.nbEtudiants);


System.out.println("Nb etudiants = "+e1.nbEtudiants);
System.out.println("Nb etudiants = "+e2. Etudiant.nbEtudiants);
}
}

ENSAM 2020-2021- T.HAJJI- 227


IV. Méthodes d’accès aux valeurs des variables depuis l’extérieur
Comment peut on accéder à la valeur d’une variable protégée ??
Exemple:
class Etudiant {
private String nom, prenom;
public Etudiant(String nom, String Prenom){
this.nom=nom; this.prenom=prenom;
}

}
public class MethodeStatic{
public static void main(String[] argv) {
Etudiant e= new Etudiant("Mohammed","Ali");
// comment afficher le nom de l’etudiant e; ??
// System.out.println("Nom = "+e.nom); ne marche pas car nom est privé
}
}

ENSAM 2020-2021- T.HAJJI- 228


Un accesseur est une méthode permettant de lire, depuis l’extérieur, le
contenu d'une donnée membre protégée.
Exemple:
class Etudiant {
private String nom, prenom;
public Etudiant(String nom, String Prenom){
this.nom=nom; this.prenom=prenom;
}
public String getNom (){
return nom;
}
}
public class MethodeStatic{
public static void main(String[] argv) {
Etudiant e= new Etudiant("Mohammed","Ali");
System.out.println("Nom = "+e.getNom());
}
}

ENSAM 2020-2021- T.HAJJI- 229


Comment peut on peut on modifier (depuis l’extérieur) le contenu d'une
donnée membre protégée ?.
Exemple:
class Etudiant {
private int cne;
public void setCNE (int cne){
this.cne=cne;
}
}
public class MethodeStatic{
public static void main(String[] argv) {
Etudiant e= new Etudiant();
// e.cne=23541654; ne marche pas car cne est un champ protégé (private)
}
}

ENSAM 2020-2021- T.HAJJI- 230


Un modificateur (mutateur) est une méthode permettant de modifier le
contenu d'une donnée membre protégée.
Exemple:
class Etudiant {
private int cne;
public void setCNE (int cne){
this.cne=cne;
}
}
public class MethodeStatic{
public static void main(String[] argv) {
Etudiant e= new Etudiant();
e.setCNT(23541654);
}
}

ENSAM 2020-2021- T.HAJJI- 231


V. Package (paquetage)

• Les classes Java sont regroupées en paquetages (packages en anglais)


comparables aux «bibliothèques» des autres langages comme le langage
C,...

• Le langage Java est fourni avec un grand nombre de paquetages

• Dans un fichier .java, on doit indiquer à quels packages appartiennent les


classes qu’on utilise à l’aide de la clause import, elle se place en début de
fichier avant la déclaration de la première classe ou interface du fichier :

import nomClasse; // Importe une classe sans package


import nomPackage.nomClasse; // Importer une classe d'un package
import nomPackage.*; // Importer toutes les classes d'un package

ENSAM 2020-2021- T.HAJJI- 232


• Le package par défaut : c’est le package qui n’a pas de nom, et auquel
appartiennent toutes les classes situées dans le même répertoire (ou dans
les répertoires accessibles dans la variable classpath)

Exemple 1:
class ClasseTest {
public ClasseTest() {
System.out.println(" Ceci est un exemple : ");
}
}
public class TestPackage {
public static void main(String[] args) {
System.out.print("Entrer un entier nouvelle largeur : ");
int i = Clavier.lireInt();
}
}

ENSAM 2020-2021- T.HAJJI- 233


Remarques:
- La compilation du fichier source TestPackage.java génère
deux fichiers .class à savoir ClasseTest.class et
TestPackage.class, ses deux fichiers appartiennent au même
package par défaut (package sans nom)

- La classe Clavier.class doit se trouver dans le même


répertoire que le fichier TestPackage.class (ou dans un
répertoire défini dans CLASSPATH), sinon le compilateur
génère une erreur.

ENSAM 2020-2021- T.HAJJI- 234


Package java.lang
Le package java.lang contenant les classes standards telles que System
• Par défaut, les classes du paquetage java.lang (contenant les classes
standards tel que System) sont automatiquement importées. Dans un
programme .java on peut faire appel à toutes les classes de java.lang
sans spécifier leur chemin.
Exemple: On peut utliser la classe Exception sans spécifier le chemin
class SimpleException extends Exception {}
qui est équivalent à
class SimpleException extends java.lang.Exception {}
ou
import java.lang.Eception;
class SimpleException extends Exception {}

ENSAM 2020-2021- T.HAJJI- 235


Accès aux package
Pour pouvoir accéder aux classes d'un package à partir d'une
classe ne faisant pas partie du package:

– il suffit de donner le chemin d'accès relatif à la classe lorsqu’on


fait appel à elle. Par exemple pour appeler la classe Button du
package java.awt, il suffit d'écrire java.awt.Button à chaque
appel de la classe Button

– Ou d'utiliser l'instruction import, suivie du chemin de la classe.


Par exemple import java.awt.Button; dans ce cas, on peut
appeler la classe Button sans spécifier le chemin.

– Ou d’importer toutes les classes d'un package. Par exemple on


importe toutes les classes du package java.awt par la syntaxe :
import java.awt.*;

ENSAM 2020-2021- T.HAJJI- 236


Remarque:
Un paquetage peut avoir des sous-paquetages, par exemple
java.awt.event est un sous-paquetage de java.awt

Attention:
L'instruction import java.awt.*; ne permet pas d’importer les
classes des sous-paquetages de java.awt
Si on veut par exemple importer les classes de java.awt et aussi
celles de java.awt.event alors on devra écrire:
import java.awt.*;
import java.awt.event.*;

ENSAM 2020-2021- T.HAJJI- 237


Quelques paquetages du SDK (Software Development Kit)

• java.lang : classes de base de Java


• java.util : utilitaires
• java.io : entrées-sorties
• java.awt : interface graphique
• javax.swing : interface graphique avancée
• java.applet : applets
• java.net : réseau
• java.rmi : distribution des objets

ENSAM 2020-2021- T.HAJJI- 238


Définition:
Pour créer un package, il suffit de commencer le fichier source
contenant les classes à regrouper par l'instruction package suivi du
nom que l'on désire donner au package.

Attention: un package portant le nom Pack1 doit être stocké dans un


répertoire de nom Pack1. De plus, pour que le compilateur puisse
trouver le package, il est essentiel qu'il "connaisse" l'emplacement
du package. Pour cela Java utilise une variable d'environnement
appelée classpath donnant la liste des chemins d'accès aux classes.

Par défaut le compilateur (ainsi que la machine virtuelle)


recherchent les classes dans le répertoire courant et le répertoire des
classes standards.

ENSAM 2020-2021- T.HAJJI- 239


Exemple
import graphics.*;
public class TestPackage1 {
public static void main(String[] args) {
Rectangle r=new Rectangle();
r.dessineRectangle();
Cercle.dessineCercle(); // méthode de classe
Triangle t=new Triangle();
t.dessineTriangle();
}
}
ENSAM 2020-2021- T.HAJJI- 240
// dans un fichier Rectangle.java situé dans le répertoire ./grahics
package graphics;
public class Rectangle{
public void dessineRectangle() { System.out.println(" Dessine un rectangle "); }
}
// dans fichier Cercle.java situé dans le répertoire ./grahics
package graphics;
public class Cercle {
public static void dessineCercle() {
System.out.println(" Dessine un cercle .... ");
}
}
// dans fichier Triangle.java situé dans le répertoire ./grahics
package graphics;
public class Triangle {
public void dessineTriangle() { System.out.println(" Dessine un triangle.... "); }
}

ENSAM 2020-2021- T.HAJJI- 241


Ch. VII. Introduction aux Interfaces
graphiques

Cette partie du cours est essentiellement développé à


partir du livre "Programmer en Java" de Claude
Delannoy, Edition Eyrolles.

ENSAM 2020-2021- T.HAJJI- 242


Les applications informatiques nécessitent des échanges
d’informations entre l’utilisateur et la machine.
Cet échange d’informations peut s’effectuer avec une interface
utilisateur (UI en anglais) en mode texte (ou console) ou en
mode graphique.
Une interface graphique est composée de plusieurs fenêtres
qui contiennent divers composants graphiques (widgets) tels
que
– boutons
– listes déroulantes
– menus
– champ texte
– etc.
Les interfaces graphiques sont souvent appelés GUI (pour
Graphical User Interface en Anglais)
ENSAM 2020-2021- T.HAJJI- 243
Il existe deux principaux types de composants
susceptibles d’intervenir dans une interface
graphique :
– les conteneurs qui sont destinés à contenir d’autres
composants, comme par exemple les fenêtres ;
– les composants atomiques qui sont des composants qui
ne peuvent pas en contenir d’autres, comme par exemple
les boutons.

ENSAM 2020-2021- T.HAJJI- 244


Java offre des facilités pour construire des interfaces graphiques
grâce aux deux bibliothèques :
– AWT (Abstract Window Toolkit, JDK 1.1)
– Swing (JDK/SDK 1.2).

Les packages principaux pour chaque bibliothèque:


– AWT : java.awt et java.awt.event
– Swing : javax.swing, javax.swing.event

Il est conseillé d’importer systématiquement toutes les classes


des paquetages pour éviter l’interrogation sur la répartition des
classes utilisées des différents paquetages
import java.awt.*;
import javax.swing.*;

ENSAM 2020-2021- T.HAJJI- 245


Afficher une fenêtre

import java.awt.*; import javax.swing.*;


class MaFenetre extends JFrame { // classe fenêtre personnalisée
public MaFenetre() {
setTitle("Ma Premiere fenetre ");
//initialisation du titre de la fenêtre
setSize(300,150);
// situé dans le coin supérieur gauche de dimension 300*150 pixels
// On peut utiliser setBounds(100,40,300,200); le coin supérieur gauche de
// la fenêtre est placé au pixel de coordonnées 100, 40 et ses dimensions
// seront de 300 *200 pixels
}
}

ENSAM 2020-2021- T.HAJJI- 246


public class TestFenetre {
public static void main(String[] args) {
JFrame fen = new MaFenetre();
fen.setVisible(true); // rend visible la fenêtre de référence fen
// on peut utiliser l’instruction
// fen.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// qui mis fin au programme lorsque la fenêtre se ferme
}
}

ENSAM 2020-2021- T.HAJJI- 247


Attention:
• Une fenêtre de type JFrame peut être redimensionnée, déplacée, et réduite
à une icône (comme une fenête Windows).
• La fermeture d'une fenêtre de type JFrame ne met pas fin au programme,
mais rend simplement la fenêtre invisible.
• Pour mettre fin au programme,
– on peut par exemple faire un Ctrl C.
– On peut appeler la méthode
JFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE) qui
permet de définir le comportement de la fenêtre lors de sa fermeture.
– Le paramètre JFrame.EXIT_ON_CLOSE indique la fin du
programme lorsque la fenêtre se ferme.

ENSAM 2020-2021- T.HAJJI- 248


Ajout d’un composant dans une fenêtre:

L’ajout d’un bouton dans le contenu d’une fenêtre se passe en 3 étapes


1. Créer une instance de la classe JButton : JButton monBouton = new JButton () ;
2. On utilise la méthode getContentPane() de la classe JFrame qui retourne une
référence, de type Container, sur le contenu de la fenêtre.
Par exemple: Container c= getContentPane();
3. On ajoute un composant dans le contenu d’une fenêtre (un objet de type
Container) en utilisant la méthode add de la classe Container.
Par exemple l’appel c.add(monBouton); permet d’ajouter l’objet de référence
monBouton dans le contenu de référence c.

La disposition des composants dans le contenu peut être gérée automatiquement


par un gestionnaires de disposition (Layout Manger en anglais) associé à chaque
container. Le gestionnaire de la classe FlowLayout permet de disposer les
composants un à coté de l’autre et ligne par ligne. La méthode setLayout(new
FlowLayout()); permet d’utiliser ce gestionnaire

ENSAM 2020-2021- T.HAJJI- 249


Ajout d’un bouton dans une fenêtre: On utilise le constructeur de la classe JButton pour
créer un bouton. Le contenu de la clase fenêtre qui sera modifié. La classe de la méthode
main() reste inchangé.

import javax.swing.*; import java.awt.*;


class MaFenetre extends JFrame {
public MaFenetre() {
setTitle(" Premier Bouton ");
setSize(300,200);
Container c=getContentPane();
// création d’un bouton de référence monBouton portant l’étiquette Un bouton
monBouton = new JButton("Un Bouton");
c.add(monBouton);
c.setLayout(new FlowLayout());
// ou tout simpolement getContentPane().setLayout(new FlowLayout());
// getContentPane().add(monBouton);

}
private JButton monBouton;
}

ENSAM 2020-2021- T.HAJJI- 250


Ajout de deux bouton dans une fenêtre:
import javax.swing.*; import java.awt.*;
class MaFenetre extends JFrame {
public MaFenetre() {
setTitle(" Plusieurs boutons ");
setSize(300,200);
boutJaune = new JButton("Bouton A");
boutVert = new JButton("Bouton B");
getContentPane().add(boutJaune);
getContentPane().add(boutVert);
getContentPane().setLayout(new FlowLayout());
boutJaune.setBackground(Color.yellow);
// La couleur de fond du composant de label Bouton A devienne jaune
boutVert.setBackground(Color.green);
// La couleur de fond du composant de label Bouton A devienne verte
}
private JButton boutJaune, boutVert;
}

ENSAM 2020-2021- T.HAJJI- 251


Programmation événementielle
Dans la programmation séquentielle c’est le programme qui garde le
contrôle des opérations(les instructions du programme principal sont
exécutées les unes après les autres dans l’ordre de leurs d’écriture).

Dans la programmation événementielle, le programme est dirigé par les


événements
• L’utilisateur pilote l’ordre d’exécution des instructions en cliquant où il
veut.
• Le programme ne fait que réagir aux actions de l’utilisateur
• Dès que vous lancez un programme avec interface graphique :
– une boucle infinie est générée
– le programme attend les événements (enfoncer une touche du clavier,
cliquer avec la souris etc.)
– Attrape et traite les événements quand ils se produisent.

ENSAM 2020-2021- T.HAJJI- 252


• Une interface graphique est basée sur 2 grandes
composantes différentes :
– L'aspect visuel qui comprend les cadres et les composants
d'interfaces qui sont placés dessus
– L'interaction avec les utilisateurs (action de la souris, du
clavier) c'est à dire en fait la gestion des événements.

ENSAM 2020-2021- T.HAJJI- 253


• Evénement = Objet construit par le système en réponse à une
action de l’utilisateur et qui contient toutes les informations
concernant cette action

Exemples: Action de l’utilisateur dans la fenêtre de l’application

• clic souris : connaissances des coordonnées du point de clic


• frappe d’un caractère : connaissance du caractère frappé

ENSAM 2020-2021- T.HAJJI- 254


Traitement des événements
En Java tout événement a une source. On appelle source d’un
événement l’objet qui a généré cet événement (exemple
bouton, fenêtre, ...).

Exemple
– L’événement émis suite à un clic souris dans une fenêtre est
de type MouseEvent
– L’événement émis suite à un clic souris sur un bouton est de
type ActionEvent

ENSAM 2020-2021- T.HAJJI- 255


Pour traiter un événement, on associe à la source, des
objets particuliers appelés écouteurs.
Par exemple on associe au bouton un « écouteur » qui va
écouter si le bouton est cliqué ou non.

En fonction des événements qu’ils traitent, un écouteur


doit implémenter une interface particulière, dérivée de
l’interface EventListener, qui correspond à une
catégorie d’événements.

ENSAM 2020-2021- T.HAJJI- 256


L’interface MouseListener correspond à une catégorie d’événements souris. Elle comporte
cinq méthodes correspondant chacune à un événement souris particulier.

public interface MouseListener extends EventListener {


public void mousePressed(MouseEvent e) ;
//appelé lorsqu’un bouton de la souris est pressé sur un composant
//l’argument e de type MouseEvent correspond à l’objet événement généré
public void mouseReleased(MouseEvent e) ;
//appelé lorsqu’un bouton de la souris est relâché sur un composant
public void mouseClicked(MouseEvent e) ;
//appelé lors d’un clic souris sur un composant (la souris n’a pas été déplacée entre
// l’appui et le relâchement du bouton)
public void mouseEntered(MouseEvent e) ;
//appelé lorsque la souris passe de l’extérieur à l’intérieur d’un composant
public void mouseExited(MouseEvent e) ;
//appelé lorsque la souris sort d’un composant (la souris passe de l’intérieur à l’extérieur
//du composant)
}

ENSAM 2020-2021- T.HAJJI- 257


Exemple 1: Gestion de clics dans une fenêtre, à chaque clic dans la fenêtre,
le message « clic dans la fenetre » s’affiche.

import java.awt.* ; import java.awt.event.* ;


import javax.swing.* ; import javax.swing.event.* ;
class MaFenetre extends JFrame {
public MaFenetre () {
setTitle("Gestion des clics ");
setBounds(10,20,300,100);
addMouseListener(new EcouteurSouris());
// la fenêtre fait appel à un écouteur d’événements souris
// pour traiter les clics souris
}
}

ENSAM 2020-2021- T.HAJJI- 258


//L’écouteur d’événements souris doit implémenter l’interface
MouseListener qui correspond à une catégorie d’événements souris.

class EcouteurSouris implements MouseListener {


//Redéfinition de la méthode appelée lors d’un clic souris
public void mouseClicked(MouseEvent e) {
System.out.println("clic dans la fenetre");
}
//La redéfinition des autres méthodes est "vide"
public void mousePressed(MouseEvent e) { }
public void mouseReleased(MouseEvent e) { }
public void mouseEntered(MouseEvent e) { }
public void mouseExited(MouseEvent e) { }
}

ENSAM 2020-2021- T.HAJJI- 259


Exemple 2: La classe fenêtre personnalisée qui implémente MouseListner
import java.awt.* ; import java.awt.event.* ;
import javax.swing.* ; import javax.swing.event.* ;
class MaFenetre extends JFrame implements MouseListener {
public MaFenetre () {
setTitle("Gestion des clics ");
setBounds(10,20,300,100);
addMouseListener(this); // la fenêtre est son propre écouteur d’événements souris
}
public void mouseClicked(MouseEvent e) {
//L’argument e correspond à l’objet événement généré dans la fenêtre lors d’un clic souris.
int x = e.getX() ;
int y = e.getY() ; //x et y coordonnées du curseur de la souris au moment du clic
System.out.println("clic dans la fenetre au point de coordonnees "+x+","+y);
}
// La redéfinition des autres méthodes est "vide"
public void mousePressed(MouseEvent e) { }
……
}
ENSAM 2020-2021- T.HAJJI- 260
La notion d’adaptateur
Pour chaque interface XXXListener (par exemple
MouseListener) possédant plusieurs méthodes, Java fournit
une classe particulière XXXAdapter (par exemple
MouseAdpter), appelée adaptateur, qui implémente toutes
les méthodes de l’interface avec un corps vide.
Pour définir un écouteur d’événements de type XXXEvent
(par exemple MouseEvent), il suffit alors de dériver
l'écouteur de la classe XXXAdapter (par exempe Mouse
Adapter) et de redéfinir uniquement les méthodes voulues.

ENSAM 2020-2021- T.HAJJI- 261


Exemple:
class MaFenetre extends JFrame {
public MaFenetre () {
super("Une fenetre qui traite les clics souris") ;
setSize(300, 200) ;
addMouseListener(new EcouteurSouris());
}
}
class EcouteurSouris extends MouseAdapter {
//redéfinition uniquement de la méthode appelée lors d’un clic souris
public void mouseClicked(MouseEvent e) {
System.out.println("clic dans la fenetre") ;
}
}

ENSAM 2020-2021- T.HAJJI- 262


Gestion des événements sur des boutons
• Un bouton ne peut déclencher qu’un seul événement
de type ActionEvent.
• L’interface ActionListener ne comporte qu’une seule
méthode actionPerformed.
• C’est à l’intérieur de la actionPerformed que nous
écrirons le code qui s’exécutera lors du click.

ENSAM 2020-2021- T.HAJJI- 263


Exemple: Clic sur un bouton affiche « Action sur Bouton Essai »
import javax.swing.*; import java.awt.*; import java.awt.event.*;
class MaFenetre extends JFrame implements ActionListener{
public MaFenetre() {
setTitle(" Premier Bouton ");
setSize(300,200);
monBouton = new JButton("Essai");
getContentPane().setLayout(new FlowLayout());
getContentPane().add(monBouton);
monBouton.addActionListener(this);
//gère l’action de l’utilisateur sur le bouton MonBouton
}
public void actionPerformed (ActionEvent ev){
System.out.println("Action sur Bouton Essai ");
}
private JButton monBouton;
}
ENSAM 2020-2021- T.HAJJI- 264
Exemple: Même classe écouteur pour tous les boutons, le clique sur un bouton affiche le
même message « Action sur Bouton Essai »
import javax.swing.*; import java.awt.*; import java.awt.event.*;
class MaFenetre extends JFrame implements ActionListener{
public MaFenetre() {
setTitle(" Deux boutons ");
setSize(300,200);
getContentPane().setLayout(new FlowLayout());
monBoutonA = new JButton("Bouton A");
getContentPane().add(monBoutonA);
monBoutonA.addActionListener(this);
monBoutonB = new JButton("Bouton B");
getContentPane().add(monBoutonB);
monBoutonB.addActionListener(this);
}
public void actionPerformed (ActionEvent ev){
System.out.println("Action sur un Bouton Essai");
}
private JButton monBoutonA, monBoutonB;
}
ENSAM 2020-2021- T.HAJJI- 265
Exemple: Même classe écouteur pour tous les boutons. L’affiche
personnalisé. L’affichage dépend du bouton cliqué

import javax.swing.*; import java.awt.*; import java.awt.event.*;


class MaFenetre extends JFrame implements ActionListener{
public MaFenetre() {
setTitle(" Premier Bouton ");
setSize(300,200);
monBoutonA = new JButton("Bouton A");
monBoutonB = new JButton("Bouton B");
Container contenu=getContentPane();
contenu.setLayout(new FlowLayout());
contenu.add(monBoutonA);
contenu.add(monBoutonB);
monBoutonA.addActionListener(this);
monBoutonB.addActionListener(this);
}
ENSAM 2020-2021- T.HAJJI- 266
public void actionPerformed (ActionEvent ev){
//utilisation de la méthode getSource de la classe EventObject qui fournit
une référence de type Object sur la source de l’événement concerné

if (ev.getSource()==monBoutonA)
System.out.println("Action sur un BoutonA");
if (ev.getSource()==monBoutonB)
System.out.println("Action sur un BoutonB");
}
private JButton monBoutonA, monBoutonB;
}

ENSAM 2020-2021- T.HAJJI- 267


Exemple: Un classe écouteur pour chaque bouton. Par exemple, le clic sur le bouton 1
ferme la fenêtre, le clic sur le bouton 2 affiche le message « action sur le bouton 2 »

import java.awt.* ; import java.awt.event.* ;


import javax.swing.* ; import javax.swing.event.* ;
class MaFenetre extends JFrame{
private JButton MonBouton1, MonBouton2 ;
public MaFenetre () {
super("Plusieurs boutons") ;
setSize(300, 200) ;
Container contenu = getContentPane() ;
MonBouton1 = new JButton("Bouton 1") ;
contenu.add(MonBouton1) ;
MonBouton2 = new JButton("Bouton 2") ;
contenu.add(MonBouton2) ;
contenu.setLayout(new FlowLayout());
MonBouton2.addActionListener(new EcouteurBouton2());
MonBouton1.addActionListener(new EcouteurBouton1());
}
}
ENSAM 2020-2021- T.HAJJI- 268
class EcouteurBouton2 implements ActionListener {
public void actionPerformed(ActionEvent e) {
System.out.println("action sur le bouton 2") ;
}
}
class EcouteurBouton1 implements ActionListener {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
}

ENSAM 2020-2021- T.HAJJI- 269


Création dynamique de plusieurs boutons

import javax.swing.*; import java.awt.*; import java.awt.event.*;


class MaFenetre extends JFrame { // implements ActionListener{
public MaFenetre() {
setTitle(" Bouton Dynamic ");
setSize(300,200);
Container contenu=getContentPane();
contenu.setLayout(new FlowLayout());
crBouton=new JButton ("CREATION BOUTON");
contenu.add(crBouton);
EcouteCr ecouteCr=new EcouteCr(contenu);
crBouton.addActionListener(ecouteCr);
}
private JButton crBouton;
}

ENSAM 2020-2021- T.HAJJI- 270


class EcouteCr implements ActionListener {
public EcouteCr(Container contenu){
this.contenu=contenu;
}
public void actionPerformed(ActionEvent ev) {
JButton nouvBout=new JButton("Bouton");
contenu.add(nouvBout);
contenu.validate();
}
private Container contenu;
}

ENSAM 2020-2021- T.HAJJI- 271


Les cases à cocher : La case à cocher de type JCheckBox permet à
l’utilisateur d’effectuer un choix de type oui/non.

Exemple
import java.awt.* ; import java.awt.event.* ;
import javax.swing.* ; import javax.swing.event.* ;
class MaFenetre extends JFrame {
private JCheckBox MaCase;
public MaFenetre () {
super("Une fenetre avec une case") ;
setBounds(10,40,300,200) ;
MaCase = new JCheckBox("Une case") ;
// création d’une case à cocher de référence MaCase portant l’étiquette Une case
getContentPane().add(MaCase) ;
}
}

ENSAM 2020-2021- T.HAJJI- 272


Par défaut, une case à cocher est construite dans l’état non coché (false). La
méthode isSelected de la classe AbstractButton permet de connaître l’état
(true ou false) d’une case à cocher à un moment donné. La méthode
setSelected de la classe AbstractButton permet de modifier l’état d’une
case à cocher.
Exemple:
MaCase.setSelected(true) ;
//coche la case de référence MaCase

ENSAM 2020-2021- T.HAJJI- 273


Quelques Références:
Livre:
- Titre: Programmer en JAVA ,
AuteurClaude Delnoy,
Editeur: Eyrolles
- Thinking in Java, Bruce Eckel
Ressources Internet:
- http://www.java.sun.com,
- http://metarisk.inapg.inra.fr/content/download, Cours Interface
graphique en Java API swing, Juliette Dibie-Barthélemy mai 2005

ENSAM 2020-2021- T.HAJJI- 274


WindowBuilder

• Window Builder est un plugin pour Eclipse qui


permet de faire la génération automatique et facile
des interfaces graphiques Swing et SWT, il permet
aussi de générer le code source java.
• Il n’est pas forcément directement intégrer dans
Eclipse mais il s’intègre facilement.
• Eclipse>Help>Eclipse Market Place > Find:
Window Builder, GO (il faut être connecter à
l’internet) puis installe!

ENSAM 2020-2021- T.HAJJI- 275


Java les collections

• Tableaux,
• Collection,
• Map
• Vues et ponts entre les structures Itération
• Legacy

ENSAM 2020-2021- T.HAJJI- 276


Structures de données
En Java, il existe 3 sortes de structures de
données
Les tableaux
● Structure de taille fixe, accès direct aux élements

Les Collections
● Structure modifiable, différents algorithmes de stockage

Les Map
● Structure modifiable, stocke des couples clé -> valeur

ENSAM 2020-2021- T.HAJJI- 277


Contrats !
Tous les algorithmes sur les structures données pré-
suppose que les classes des objets stockés respect un
certain contrat

Il vous faudra peut-être pour cela implanter correctement


equals, hashCode, toString ou compareTo sur les objets
de la collection

Si ce n'est pas le cas, au mieux une exception est levée,


au pire cela fait n'importe quoi
ENSAM 2020-2021- T.HAJJI- 278
Exemples
public class StupidInteger {
private final int value;
public StupidInteger(int value) {
this.value = value;
}
}
StupidInteger[] array = new StupidInteger[1];
array[0] = new StupidInteger(1);
Arrays.sort(array); // ClassCastException
HashSet<StupidInteger> set = new HashSet<>();
set.add(new StupidInteger(1));
set.contains(new StupidInteger(1)); // renvoie false !

ENSAM 2020-2021- T.HAJJI- 279


Null comme valeur d'une collection
•Stocker null dans une collection n'est pas une bonne idée car
cela plantera quand on sortira l'élement de la collection
•De plus, en fonction des versions du JDK, null est accepté ou
non
•1.0, 1.1, null est pas accepté
•HashTable, Vector, Stack
•1.2, 1.3, 1.4, null est accepté
•HashMap, ArrayList, etc
•1.5 ..., null est pas accepté
•PriorityQueue, ArrayDeque, etc)
ENSAM 2020-2021- T.HAJJI- 280
Null comme Collection
On utilise jamais null lorsque l'on s'attend à avoir un tableau ou
une Collection
public Collection<String> getFoo() {
return null; // ahhh, utiliser Collections.emptyCollection()
}
public String[] getBar() {
return null; // ahhhh, utiliser NULL_ARRAY
}
private static final String[] NULL_ARRAY = new String[0];

Il existe des collections vide qui sont des constantes,


Collections.emptySet(), Collections.emptyList(), etc.
ENSAM 2020-2021- T.HAJJI- 281
Les tableaux
Ils ont une taille fixe définie à l'initialisation et sont toujours
mutable (copie défensive!)
Les tableaux sont spécialisés pour les types primitifs
–byte[], int[], long[], double[]
–Ils n'héritent pas de Object[] mais de Object
Pour les tableaux d'objets, les cases sont initialisés à null (=>
ahhh), pour les primitifs, les cases sont initialisé à false, 0,
0.0

ENSAM 2020-2021- T.HAJJI- 282


Les tableaux
Les tableaux hérite de Object (ou Object[] qui
hérite de Object) et n'ont pas les méthodes toString,
equals et hashCode redéfinie en fait seul clone() est
redéfinie

Quasiment toutes les méthodes (statique) de


manipulation des tableaux sont regroupés dans
java.util.Arrays

ENSAM 2020-2021- T.HAJJI- 283


Algos classiques (java.util.Arrays)
fill() remplie un tableau (memset en C) copies
–System.arrayCopy (memcopy comme en C)
–Arrays.copyOf() (créé et recopie un tableau + grand
ou + petit)
–Object.clone()
duplique mais on utilise plutôt
Arrays.copyOf(array, array.length)
toString, deepToString, equals, hashCode, etc

ENSAM 2020-2021- T.HAJJI- 284


Collection
L'interface java.util.Collection est l'interface de base de
toutes les structures de donnée qui stocke des éléments
Il existe 4 sous-interfaces
–Set, ensemble sans doublon
–List, les listes ordonées et indexées
–Queue, les files (FIFO)
–Deque, les files “double ended”

ENSAM 2020-2021- T.HAJJI- 285


Collection<E> paramétrée
Les collections sont homogènes, elle
contiennent des éléments qui ont le même type
(pas forcément la même classe) donc elles sont
paramétrés par une variable de type, souvent
nommée E pour type d'un élément

ENSAM 2020-2021- T.HAJJI- 286


Collection et type primitif
Les collections ne sont pas spécialisées pour les types primitfs,
ce sont des collections d'objet

On utilise le boxing/unboxing si il n'y a pas d'exigence de


performance
ArrayList<Integer> list = new ArrayList<>();
list.add(1); // boxing en Integer.valueOf(1)
int value = list.get(0); // unboxing avec .intValue()

attention si on stocke null dans la list, il y aura un NullPointerException

ENSAM 2020-2021- T.HAJJI- 287


Collection et taille
A l'exception des collections concurrentes, toutes
les collections maintiennent une taille accessible
en temps constant (O(1))
int size()
permet d'obtenir la taille (sur 31 bits)
boolean isEmpty()
permet de savoir si la collection est vide

ENSAM 2020-2021- T.HAJJI- 288


Collection & mutabilité
Les Collections sont mutables par défaut
boolean add(E)
● Ajoute un élement, renvoie vrai si la collection est modifiée
boolean remove(Object)
Supprime un élement, renvoie vrai si la collection est modifiée
boolean removeIf(Predicate<? super E> predicate)
Supprime un élement si le predicate est vrai, renvoie vrai si la
collection est modifiéevoid clear()
Supprime tous les élements d'une collection (peu utilisée)

ENSAM 2020-2021- T.HAJJI- 289


Operations optionnelles
• Les opérations de mutations (add, remove, clear,
addAll, etc) peuvent levées l'exception
UnsupportedOperationException pour dire que dire que
l'opération n'est pas supportée
• Cela permet de représenter des collections non-
mutable ou des collections mutables mais de taille fixe

ENSAM 2020-2021- T.HAJJI- 290


Collection non mutable
Collections.unmodifiableCollection() permet de créer
un proxy implantant seulement les opération non-
optionnel devant une collection modifiable
ArrayList<String> list = new ArrayList<>();
List<String> list2 = Collections.unmodifiableList(list);
list2.add("hello"); // UnsupportedOperationException

list.add("hello"); // ok
list2.size(); // renvoie 1
Cela permet d'éviter les copie défensive !
ENSAM 2020-2021- T.HAJJI- 291
Object ou E ?
Pourquoi remove(Object) et add(E) ?
A cause des interfaces interface I {}
interface J {}
class A implements I, J {}
public static void main(String[] args) {
Collection<I> collection = ...
A a = new A();
collection.add(a);// ok, A est un sous-type de I J
j = a;
collection.remove(j); // doit être valide
}
ENSAM 2020-2021- T.HAJJI- 292
Recherche
java.util.Collection possède une méthode de recherche
boolean contains(Object)
Renvoie vrai si l'objet est stocké dans la collection
Note sur la complexité:
contains (ou add, remove, etc.) a une complexité différente suivant
la structure de donnée
contains pour une HashSet est O(1), pour un TreeSet est O(ln n) et pour une
ArrayList O(n)

ENSAM 2020-2021- T.HAJJI- 293


Les méthodes de object
equals, hashCode et toString sont implantés et
délègue à l'implantation des élements de la
collection
Cela permet d'ajouter une collection à une
collection mais dans ce cas la collection ajoutée ne
doit pas être modifiée à postériori !
Ajouter des objets mutables à une collection est
poetentiellement dangereux !

ENSAM 2020-2021- T.HAJJI- 294


Exemple
ArrayList<String> list = new ArrayList<>();
HashSet<List<String>> set = new HashSet<>();
set.add(list);
list.add("hello");
set.contains(list); // false

note, si on a pas de chance, set.contains(list) peut renvoyer


vrai car même si la valeur de hashCode a changé, la liste
peut être rangée dans la même case de la table de hachage

ENSAM 2020-2021- T.HAJJI- 295


Bulk (opérations groupées)
Les méthodes groupés:
boolean addAll(Collection<? extends E>)
ajoute tous les élements de la collection dans this
boolean removeAll(Collection<?>)
supprime les élements de this qui sont aussi dans la collection
boolean retainAll(Collection<?>)
retient dans this les élements qui appartiennent à this et à la collection (intersection)
boolean containAll(Collection<?>)
renvoie vrai si this contient tous les élements de la collection

ENSAM 2020-2021- T.HAJJI- 296


Bulk
addAll(), par exemple, est équivalent à
public boolean addAll(Collection<? extends E> c) {
boolean result = false;
for(E element: c) {
result |= this.add(element);
}
return result;
}
mais peut être écrite de façon plus efficace en fonction de
l'implantation

ENSAM 2020-2021- T.HAJJI- 297


Les concepts de collections
Il existe 4 sous-interfaces
– Set, ensemble sans doublon
– List, les listes ordonées et indexées
– Queue, les files (FIFO)
– Deque, les files “double ended”

ENSAM 2020-2021- T.HAJJI- 298


java.util.Set
Ensemble d'élements sans doublons
Par ex. les options de la ligne de commande

Exactement la même interface que Collection, la sémantique


des méthodes est pas la même
par ex, add() renvoie false si doublons

ENSAM 2020-2021- T.HAJJI- 299


Implantations de Set
HashSet
table de hachage
Ensemble sans ordre, add/remove en O(1)
LinkedHashSet
Table de hachage + list chainée
Ordre d'insertion (ou d'accès), add/remove en O(1)
TreeSet
Arbre rouge/noir (ordre de comparaison)
Ordre par un comparateur, add/remove en O(ln n)
EnumSet
Bit set
Ordre des valeurs de l'enum, add/remove en O(1)

ENSAM 2020-2021- T.HAJJI- 300


Exemple
Détecter des doublons dans les arguments de la ligne de commande

public static void main(String[] args) {


HashSet<String> set = new HashSet<>();
for(String arg: args) {
if (!set.add(arg)) {
System.err.println("argument " + arg + " specified
twice"); return;
}
}
}

ENSAM 2020-2021- T.HAJJI- 301


java.util.List
Liste d'élement indexé conservant l'ordre d'insertion
Par ex, la liste des vainqueurs du tour de France

Méthodes supplémentaires
E get(int index), E set(int index, E element)

accès
● en utilisant un index
int indexOf(E element), lastIndexOf(E element)
comme
● contains mais qui renvoie un index ou -1
void sort(Comparator<? Super E>)
Trie
● en fonction d'un ordre de comparaison

ENSAM 2020-2021- T.HAJJI- 302


Implantations de List
ArrayList
Tableau dynamique
Ajout à la fin en 0(1), ajout au début en O(n), accès indexé en O(1)

LinkedList
List doublement chaînée
Ajout à la fin en 0(1), ajout au début en O(1), accès indexé en O(n)

ENSAM 2020-2021- T.HAJJI- 303


Problème de l'interface List
java.util.List est pas une interface dangereuse en terme de
complexité
–Accès indexé à une LinkedList est en O(n)
–ajouter un élement en tête d'une ArrayList est en O(n)

On accède pas de façon indexée à une java.util.List, pas de


problème si c'est une ArrayList

ENSAM 2020-2021- T.HAJJI- 304


java.util.RandomAccess
Les listes à accès indexées en tant constant doivent implanter
java.util.Random (marker interface)
Il est possible de tester à l'exécution l'accès indexée est en temps
constant list instanceof RandomAccess
Note: ce n'est pas exactement ce que dit la doc de l'interface
RandomAccess mais c'est vrai en pratique

ENSAM 2020-2021- T.HAJJI- 305


Liste ou tableau ?
Si on connait le nombre d'éléments, on utilise plutôt un
tableau car c'est plus efficace

Mais un tableau de type paramétré est unsafe


Il est habituelle dans du code utilisateur d'utiliser
List<Set<String>> au lieu de Set<String>[]

Il est aussi possible de voir un tableau comme une liste (cf


plus tard)

ENSAM 2020-2021- T.HAJJI- 306


Exemple
private static int sum(List<Integer> list) {
int sum = 0;
for(int i = 0; i < list.size(); i++) { sum += Ne jamais écrire ça !
list.get(i);
}
return sum;
}
public static void main(String[] args) {
List<Integer> list;
if (args[0].equals("linked")) {
list = new LinkedList(1_000_000);
} else {
list = new ArrayList(1_000_000);
}
for(int i = 0; i < 1_000_000; i++) {
list.add(i);
} System.out.println(sum(list)); // si list est une LinkedList, c'est long !
}
ENSAM 2020-2021- T.HAJJI- 307
java.util.Queue
Représente une file d'élements FIFO
(la convention est ajout à la fin et retire au début)
– Par ex, une file d'attente

Méthodes supplémentaires
boolean offer(E)
ajoute à la fin, renvoie vrai si ajouté
E poll()
retire en tête, null si vide
E peek()
regarde l'élement en tête sans le retirer, null si vide
ENSAM 2020-2021- T.HAJJI- 308
Implantations de Queue
ArrayDeque
Tableau dynamique circulaire
Ajout/suppression en O(1)
PriorityQueue
Tas (ordre de comparaison)
Ajout/suppression en O(ln n)
LinkedList
Liste double chainée
Ajout/suppression en O(1)
ENSAM 2020-2021- T.HAJJI- 309
Autre sémantique
En plus de offer/poll/peek, il existe 3 autres méthodes
qui ont la même sémantique mais plante au lieu de
renvoyer null/false, elles sont peu utilisées en pratique

boolean add(E element)


comme offer() mais lève IllegalArgumentException si plein
E remove()
comme poll() mais lève NoSuchElementException si vide
E element()
comme peek() mais lève NoSuchElementException si vide

ENSAM 2020-2021- T.HAJJI- 310


Exemple
public class Tree {
private final int value;
private final Tree left, right;
public Tree(int value, Tree left, Tree right) { t
his.value = value;
this.left = left;
this.right = right;
}
public void breadthSearch(Consumer<? super Tree> consumer) {
ArrayDeque<Tree> queue = new ArrayDeque<>();
queue.offer(this);
while (!queue.isEmpty()) {
Tree tree = queue.poll();
consumer.accept(tree);
Tree left = tree.left, right = tree.right;
if (left != null) { queue.offer(left); }
if (right != null) { queue.offer(right); }
}
}
public static void main(String[] args) {
Tree tree = ...
tree.breadthSearch(System.out::println);
}
}
ENSAM 2020-2021- T.HAJJI- 311
java.util.Deque
Sous-type de Queue qui permet d'ajouter ou retirer en début ou en fin de
la file
Méthodes supplémentaires
boolean offerFirst(E), boolean offerLast(E)
ajouté au début ou à la fin
E pollFirst(), E pollLast()
retirer au début ou à la fin
E peekFirst(E), E peekLast()
voir sans retirer au début ou à la fin et aussi addFirst(E), addLast(E), E removeFirst(), E
removeLast(), E getFirst(), E getLast()

ENSAM 2020-2021- T.HAJJI- 312


Map
Appelée aussi table associative ou dictionnaire une
map fonctionne avec deux élements
–un élement clé (de type K) et
–un élement valeur (de type V)

Les clés insérés n'ont pas de doublons


Il est possible d'avoir des doublons au niveau des
valeurs

ENSAM 2020-2021- T.HAJJI- 313


java.util.Map<K,V>
méthodes
V put(K key, V value)
insére un couple clé/valeur et supprime si il existe le couple clé/valeur
précédent ayant la même clé, renvoie l'ancienne valeur ou null
V get(Object key)
renvoie la valeur correspondant à une clé ou null si il n'y a pas de couple
clé/valeur ayant la clé key
isEmpty() et size()
renvoie si la map est vide/le nombre de couples clé/valeur

ENSAM 2020-2021- T.HAJJI- 314


Implantations
HashMap
Table de hachage sur les clés
Les couples ne sont pas ordonées, insertion/accès/suppression en O(1)
LinkedHashMap
Table de hachage sur les clés + liste doublement chaînée
Couples ordonnées par ordre d'insertion (ou d'accès), insertion/accès/suppression en O(1)
TreeMap
Arbre rouge noir (ordre de comparaison)
Couple ordonée suivent l'ordre de comparaison, insertion/accès/suppression en O(ln n)
IdentityHashMap
Table de hachage fermé, ==/System.identityHashCode pour le test égalité/hashCode
Couple non ordonée, insertion/accès/supression en O(1)
WeakHashMap
Table de hachage avec clés stocké dans des références faibles
Couple non ordonée, insertion/accès/supression en O(1)

ENSAM 2020-2021- T.HAJJI- 315


Obtenir un couple
en plus de get(), il existe les méthodes
V getOrDefault(V defaultValue)
permet de renvoyer une valeur par défaut au lieu de null comme pour get
V computeIfAbsent(K key, Function<K,V> fun)
renvoie la valeur associée à la clé, si il n'y a pas de valeur, appel la fonction
pour obtenir valeur et enregistre le couple clé/valeur (pratique pour un
cache)
boolean containsKey()
permet de savoir si la clé existe, très peut utilisé car
–soit cela veut dire que l'on veut un Set
–soit que l'on va faire un get() derrière dans ce cas autant faire un get() uniquement

ENSAM 2020-2021- T.HAJJI- 316


Insérer/supprimer un couple
en plus de put(), il existe les méthodes
V putIfAbsent(K key,V value)
comme put mais n'ajoute pas un couple existe déjà

V remove(Object key)
boolean remove(Object key, Object value)
supprime un couple (à partir de la clé, ou du couple)

V replace(K key, V value)


boolean replace(K key, V oldValue, V newValue)
remplace un couple (à partir de la clé, ou du couple)

ENSAM 2020-2021- T.HAJJI- 317


bulk
Opérations groupées
void putAll(Map<? extends K, ? extends V> map)
insére tous les élements de map dans this

void replaceAll(BiFunction<? super K, ? super V,


? extends V> fun)
remplace toutes les valeurs des couples existant dans la Map par de nouvelles
fournies pas la fonction

Il n'y a pas de removeAll(map) car cela peut être fait sur


l'ensemble des clés (cf suite du cours)
ENSAM 2020-2021- T.HAJJI- 318
Map.Entry<K,V>
interface interne de l'interface Map, représente des couples
clé/valeur mutable

Opérations
K getKey()
renvoie la clé du couple
V getValue()
renvoie la valeur du couple
V setValue(V value)
change la valeur du couple (opération mutable optionelle)

ENSAM 2020-2021- T.HAJJI- 319


Implantations de Map.Entry
Map.Entry possède deux implantations, déclarés
bizarrement en tant que classe interne de AbstractMap
implantent aussi equals/hashCode/toString

AbstractMap.SimpleImmutableEntry<K,V>
version non mutable, setValue jète une UOE

AbstractMap.SimpleEntry<K,V>
version mutable, equals/hashCode/toString passe par les getters et donc ils
peuvent être redéfinie

ENSAM 2020-2021- T.HAJJI- 320


Exemple
Calculer un histogramme d'occurences

public static <T> void histo(


List<? extends T> list, Map<? super T, Integer> map) {
for(T element: list) {
map.put(element, 1 + map.getOrDefault(element, 0));
}
}
public static void main(String[] args) {
HashMap<String, Integer> map = new HashMap<>();
histo(Arrays.asList(args), map);
System.out.println(map);
} ENSAM 2020-2021- T.HAJJI- 321
Exemple
public class Trie {
private boolean terminal;
private final HashMap<Character,Trie> map = new HashMap<>();
public void add(String s) {
Trie trie = this;
for(int i = 0; i < s.length(); i++) {
char letter = s.charAt(i);
trie = trie.map.computeIfAbsent(letter, l -> new Trie());
}
trie.terminal = true;
}
public boolean contains(String s) {
Trie trie = this;
for(int i = 0; i < s.length(); i++) {
char letter = s.charAt(i);
trie = trie.map.get(letter);
if (trie == null) {
return false;
}
}
return trie.terminal;
}
}
ENSAM 2020-2021- T.HAJJI- 322
Pont et vue entre les collections
Il existe deux types méthodes de “conversions”
–Copier les données d'une structure vers une nouvelle
les données sont dupliquer dans la nouvelle structure

–Voir une structure de donnée comme une autre


les données reste dans la structure initiale et sont aussi vue dans la
nouvelle structure, on parle de vue

ENSAM 2020-2021- T.HAJJI- 323


Interopération par copie
Collection vers les tableaux
Object[] Collection.toArray()
Créer un tableau d'Object

<T> T[] Collection.toArray(T[] array)


Utilise le tableau pris en paramètre, ou crée un nouveau tableau si le tableau
est trop petit
– si le tableau est trop grand, on met null après le dernier élement ??

ENSAM 2020-2021- T.HAJJI- 324


Interopération par copie
Collection vers Collection
Toutes les collections ont un constructeur qui prend une
Collection<? extends E>
Sur une collection addAll(Collection<? extends E>) permet
d'ajouter

Tableau vers Collection


<T> Collections.addAll(Collection<? super T> coll, T... array)

ENSAM 2020-2021- T.HAJJI- 325


Interopération par vue
Tableau vers List
<T> List<T> Arrays.asList(T... array)

List vers List


list.subList(int start, int end) permet d'obtenir une sous-liste d'une liste

Map vers Set


Set<E> Collections.newSetFromMap(
Map<E, Boolean> map)

Queue vers Queue


Queue<T> Collections.asLifoQueue(
Deque<T> deque)
ENSAM 2020-2021- T.HAJJI- 326
Interopération par vue
Map vers l'ensemble des clés
Set<K> map.keySet()

Map vers la collection des valeurs


Collection<V> map.values()

Map vers l'ensemble des couples clé/valeur


Set<Map.Entry<K,V>> map.entrySet()

ENSAM 2020-2021- T.HAJJI- 327


Exemple
Il n'existe pas de méthode contains() ou shuffle() qui prend en
paramètre un tableau dans java.util.Arrays mais en utilisant une
vue ...
public static void main(String[] args) {
List<String> list = Arrays.asList(args);
list.contains("bingo");
// search if "bingo" is contained in args
Collections.shuffle(list);
// the array args is now suffled
}

ENSAM 2020-2021- T.HAJJI- 328


Itération Interne vs Externe
Il existe deux types d'itération sur une collection
–Itération interne
On envoie du code (sous forme de lambda) à exécuter par la structure de donnée,
la structure parcours sa structure et pour chaque élement appel la lambda avec
l'élement en paramètre
–Itération externe
On demande à la collection un curseur (un Iterator) qui va servir à parcourir la
collection en retournant un élement à chaque appel

java.util.Iterable sert d'interface pour les 2 façons d'itérer

ENSAM 2020-2021- T.HAJJI- 329


Itération interne
Iterable.forEach(Consumer<? super E> consumer) avec
@FunctionalInterface
public interface Consumer<T> {
public void accept(T t);
}

exemple : List<String> list = ...


list.forEach(e -> System.out.println(e));

ENSAM 2020-2021- T.HAJJI- 330


Itération interne sur une Map
Map.forEach(BiConsumer<? super K, ? super V> bc) avec
@FunctionalInterface
public interface BiConsumer<T, U> {
public void accept(T t, u u);
}

exemple :
Map<String, Option> map = ... map.forEach((key, value) -> {
System.out.println("key: " + key + " value: " + value);
});

ENSAM 2020-2021- T.HAJJI- 331


Iteration externe
Iterator<E> Iterable.iterator()
avec
public interface Iterator<E> {
public boolean hasNext(); existe t'il un élement suivant ?
la méthode n'a pas d'effet de bord
public E next();
}
renvoie l'élement courant et passe au
suivant ou NoSuchElementException
exemple :
List<String> list = ...
Iterator<String> it = list.iterator(); // on récupère le 'parcoureur'
while(it.hasNext()) {
System.out.println(it.next());
}
ENSAM 2020-2021- T.HAJJI- 332
Position de l'itérateur
A la création :
e1 e2 e3 e4 e5 e6

Itérateur au début

Après un appel à iterator.next() :

e1 e2 e3 e4 e5 e6

L'itérateur est après le premier élement

Si hasNext() renvoie false :


e1 e2 e3 e4 e5 e6

Itérateur est après le dernier élement


ENSAM 2020-2021- T.HAJJI- 333
Syntaxe pour l'itération externe
La boucle for(type var: iterable) sur un Iterable
est transformé en
Iterator<type> it = iterable.iterator(); while (it.hasNext()) {
type var = it.next();
...
}

Attention à ne pas confondre avec


for(type var: array) qui parcours le tableau avec des index

ENSAM 2020-2021- T.HAJJI- 334


Ecrire son itérateur
2 phases
–On écrit le code itératif sans itérateur
–On répartit le code dans l'itérateur

Par exemple, avec un code d'itération interne


public class MyArray<E> {
private final E[] array;
...
public void forEach(Consumer<? super E> consumer) {
for(int i = 0; i < array.length; i++) {
E element = array[i]; consumer.accept(element);
}
}}

ENSAM 2020-2021- T.HAJJI- 335


Ecrire son itérateur (2)
public class MyArray<E> { private final E[] array;
...
public void forEach(Consumer<? super E> consumer) { for(int i
= 0; i < array.length; i++) {
E element = array[i]; consumer.accept(element);
}
}
condition
public Iterator<E> iterator() { return new Iterator<E>() { public
boolean hasNext() {
...
}
public E next() {
...
renvoie de l'élement +
} incrémentation
}
}
}

ENSAM 2020-2021- T.HAJJI- 336


Ecrire son itérateur (3)
public class MyArray<E> { private final E[] array;
...
public void forEach(Consumer<? super E> consumer) { for(int i
= 0; i < array.length; i++) {
E element = array[i];
consumer.accept(element);
}
}

public Iterator<E> iterator() {


return new Iterator<E>() {
private int i = 0;
public boolean hasNext() { La variable locale i se
return i < array.length; transforme en champ
}
public E next() {
E element = array[i]; i++;
return e;
}
}
}
}
ENSAM 2020-2021- T.HAJJI- 337
Attention cet Iterateur est FAUX !
Interface Iterator !
L'interface Iterator n'oblige pas à ce que
hasNext() et next() soit appelé dans cette ordre

Il faut vérifier qu'un code utilisateur puisse


appeler
–hasNext() plusieurs fois sans appel à next()
–next() sans appeler une seul fois hasNext()

ENSAM 2020-2021- T.HAJJI- 338


Ecrire son itérateur (3)
public class MyArray<E> { private final E[] array;
...
public void forEach(Consumer<? super E> consumer) { for(int i
= 0; i < array.length; i++) {
E element = array[i];
consumer.accept(element);
}
} next() peut être appelée sans
public Iterator<E> iterator() { return new Iterator<E>() { private appel à hasNext()
int i = 0;
public boolean hasNext() { return i < array.length;
}
public E next() {

if (!hasNext()) { throw new NoSuchElementException(); }


E element = array[i]; i++;
return e;
}
}
}
}

ENSAM 2020-2021- T.HAJJI- 339


Mutation de la collection et itération
Il est interdit d'effectuer une mutation sur la structure de
donnée durant l'itération !
Itération interne : Set<String> set = ... set.forEach(e ->
set.add(e));
// throws ConcurrentModificationException
Itération externe : Set<String set = ... for(String e: set) {
set.add(e);
}
// throws ConcurrentModificationException

ENSAM 2020-2021- T.HAJJI- 340


ConcurrentModificationException
Exception levée lorsque durant le parcours, on modifie la
structure de donnée sur laquelle on itére
Le nom de l'exception est vraiment pas terrible
Concurrent veut dire normalement accéder par différents fils
d'exécution (thread) mais ce n'est pas le cas ici :

La technique qui consiste lors du parcours à regarder si une


mutation a été effectuée ou pas est appelée fail-fast.

ENSAM 2020-2021- T.HAJJI- 341


Mutations lors du parcours
Il est possible d'éviter la lévée de
ConcurrentModificationException dans le cas d'une
itération externe, car il est possible de faire les mutations
directement sur l'itérateur
–Iterator possède une méthode remove()
–ListIterator qui est une version spécialiser de l'itérateur (et donc
hérite de Iterator) pour les listes possèdes en plus les méthodes
add() et set()

ENSAM 2020-2021- T.HAJJI- 342


Iterator.remove
Méthode par défaut dans Iterator
Supprime l'élement qui a été renvoyer
précédemment par next()

donc next() doit être appelé d'abord

Il n'est donc pas possible de faire 2 removes de suite sans
appeler next() entre les deux

Lève IllegalStateException si next pas appelé avant

L'implantation par défaut (Java8) dans Iterator lève


UnsupportedOperationException

ENSAM 2020-2021- T.HAJJI- 343


Exemples
Exemple qui ne marche pas (CME) :
LinkedList<String> list = ... for(String s: list) {
if (s.length() % 2 == 0) {
list.remove(s); // la complexité est affreuse aussi
}
}
Exemple qui marche : Iterator<String> it = list.iterator();
while(it.hasNext()) {
String s = it.next();
if (s.length() % 2 == 0) { it.remove();
}
}

ENSAM 2020-2021- T.HAJJI- 344


Iteration à l'envers
Sur une List, il est possible de parcourir celle-ci du dernier élement au
premier en utilisant le ListIterator

Exemple: List<String> list = ...


ListIterator<String> it = list.listIterator(list.size);
// on place l'itérateur à lafin
while(it.hasPrevious()) {
String s = it.previous();
...
}

ENSAM 2020-2021- T.HAJJI- 345


Parcours indexé
Attention, le parcours indexé peut être mortel
Exemple :
List<String> list = ...
for(int i = 0, i < list.size(); i++) { String s = list.get(i);
...
}
Si list.get() est pas en temps constant, alors la complexité est
O(n2)

L'itération external ce se fait avec l'Iterator à part si on est sûre


que la liste implante RandomAccess.

ENSAM 2020-2021- T.HAJJI- 346


Itération interne vs externe
L'itération interne est souvent plus efficace car
–Il n'y a pas deux appels (hasNext()/next())
–Les checks de mutation (failfast) peuvent être fait une seul fois à la fin
mais comme on envoie une lambda à iterable.forEach(), on est
limité par le fait qu'une lambda n'est pas une closure
il n'est pas possible d'effectuer des mutations sur les variables locales à
l'intérieur d'une lamnbda
L'itération externe permet aussi la composition d'itérateurs

ENSAM 2020-2021- T.HAJJI- 347


Ordre et trie
Pour pouvoir trier ou ordoner des objects, il faut une
fonction de comparaison

Il y a deux sortes de façon de specifier un ordre en Java


–Ordre des élements, l'ordre est définie sur les élements de la
collection grâce à l'interface Comparable
–Ordre
externe, l'ordre est spécifier par un objet externe un
Comparator

ENSAM 2020-2021- T.HAJJI- 348


Ordre des élements
Ordre des élements ou ordre naturel est spécifié en
implantant l'interface Comparable
public interface Comparable<E> {
int compareTo(E element);
}
a.compareTo(b) < 0 <=> a < b
a.compareTo(b) > 0 <=> a > b
a.compareTo(b) == 0 <=> a == b
CompareTo doit marcher avec equals,
a.compareTo(b) <=> a.equals(b) == true

ENSAM 2020-2021- T.HAJJI- 349


Ordre extérieur
Un ordre extérieur est une fonction de
comparaison externe. Cela permet de spécifier un
autre ordre que l'ordre naturel.

public interface Comparator<T> {


int compare(T t1, T t2);
}

compare doit aussi être compatible avec equals,


compare(a, b) == 0 <=> a.equals(b) == true

ENSAM 2020-2021- T.HAJJI- 350


Exemple
En utilisant l'ordre naturel, java.lang.String
implante l'interface Comparable
String[] array = new String[] { "foo", "bar" };
Arrays.sort(array);

En utilisant un ordre externe


List<String> list = Arrays.asList("foo", "bar");
list.sort((s1, s2) -> s1.trim().compare(s2.trim());

ENSAM 2020-2021- T.HAJJI- 351


Implanter un Comparable ou un
Comparator
Trouver les 2 bugs ?

public class Point implements Comparable<Point> {


private final int x;
private final int y;
public Point(int x, int y) { … }
public int compareTo(Point p) {
int dx = x – p.x;
if (dx != 0) { return dx; }
return y – p.y;
}
} ENSAM 2020-2021- T.HAJJI- 352
Implanter un Comparable ou un
Comparator
Il manque le equals() et il y a un problème d'overflow

public class Point implements Comparable<Point> {


private final int x;
private final int y;
public int compareTo(Point p) {
int dx = Integer.compare(x, p.x);
if (dx != 0) { return dx; }
return Integer.compare(y, p.y);
}

public boolean equals(Object o) {


if (!(o instanceof Point)) { return false; }
Point p = (Point)o;
return x == p.x && y == p.y;
}
}
ENSAM 2020-2021- T.HAJJI- 353
Comparaison par rapport à un champs

• Comparator possède des méthodes statique


comparing(), comparingInt(), etc. de comparaison
par rapport à un champ

• public class Author { private final String name;


• public String getName() { return name; }
• ...
• }
• List<Author> list = ...
list.sort(Comparator.comparing(Author::getName));
ENSAM 2020-2021- T.HAJJI- 354
Trier
Il y a deux solutions
Utiliser une collection qui garde un ordre new
TreeSet<E>(Comparator<? super E> c) new TreeMap<K,V>(Comparator<?
super K> c)
On a un ordre uniquement sur les clés

Trier une collection


list.sort(Comparator<? super E> c)
<T> Arrays.sort(T[], Comparator<? super T> c)
<T> Arrays.parallelSort(T[], Comparator<? super T> c)
Ils existent aussi des versions pour les types primitifs

ENSAM 2020-2021- T.HAJJI- 355


BinarySearch
Pour faire une recherche dichotomique (couper en deux)
sur un tableau
Arrays.binarySearch(T[] array, T element,
Comparator<? super T> c)

sur une liste


<T> Collections.binarySearch(List<? extends T> list,
T element, Comparator<? super T> c)

Il faut pas oublier que la structure doit être triée !

ENSAM 2020-2021- T.HAJJI- 356


NavigableSet
interfaces sous-type de Set qui permet d'obtenir pour une valeur
l'élement précédent ou suivant de la collection
Opérations
E floor(E) <=, lower(E) <, ceiling(E) >=, higher(E) >

Recherche d'un élement
NavigableSet<E> headSet(E element, boolean inclusive)
NavigableSet (vue) entre first() et element
NavigableSet<E> subSet(E from, boolean, E to, boolean)
NavigableSet (vue) entre from et to
NavigableSet<E> tailSet(E element, boolean inclusive)
NavigableSet (vue) entre element et last()

ENSAM 2020-2021- T.HAJJI- 357


NavigableMap
interfaces sous-type de Map,
permet d'obtenir pour une valeur (de type clé K) le couple
clé/valeur précédent/suivant
Opérations
Entry<K,V> floorEntry(K) <=, lowerEntry(K) <, ceilingEntry(K) >=,
higherEntry(K) >
NavigableMap<K,V> headMap, subMap, tailMap
NavigableKeySet<K> navigableKeySet()
Ensemble des clés sous forme d'un navigable set
NavigableMap<K,V> descendingMap()
this mais en ordre décroissant
ENSAM 2020-2021- T.HAJJI- 358
Legacy collection
java.util existe depuis 1.0 mais API des collections
existe que depuis la version 1.2
Vector, Stack, Hashtable et Enumeration sont des
anciennes classes
–qui ne doivent plus utilisé à part pour discuter avec du
code legacy
–Les 4 premières ont des problèmes de performance car
leurs méthodes sont synchronized

ENSAM 2020-2021- T.HAJJI- 359


Classe de remplacement
Les classes de remplacement ont la même API (ou
une API très similaire) que les classes legacy

Vector -> ArrayList


Stack -> ArrayDeque
Hashtable -> HashMap
Enumeration -> Iterator
plus la méthode Collections.list(enumeration) -> List

ENSAM 2020-2021- T.HAJJI- 360


Exemple
Récupérer l'ensemble des interfaces réseaux
Enumeration<NetworkInterface> enumeration =
NetworkInterface.getNetworkInterfaces();
List<NetworkInterface> interfaces =
Collections.list(enumeration); // hop on triche

for(NetworkInterface networkInterfaces: interfaces) {


System.out.println(networkInterfaces);
}

ENSAM 2020-2021- T.HAJJI- 361


Abstract helper
Si l'on veut créer sa propre collection pour par exemple
implanter une vue, il existe déjà des classes abstraites que
l'on peut redéfinir
–AbstractCollection,

–AbstractSet

–AbstractQueue

–AbstractMap

–AbstractList / AbstractSequentialList
Pour les listes AbstractSequentialList hérite de AbstractList ce qui est une
erreur de design !

ENSAM 2020-2021- T.HAJJI- 362


Abstract helper
Les classes abstraites
–Demande d'implanter une ou deux méthodes abstraites
–Fournissent une implantation des autres méthodes non
optionelles en utilisant l'implantation des méthodes abstraites

Comme les méthodes optionnels ne sont pas implanter,


la collection est par défaut non mutable
pour avoir une version mutable il faut aussi redéfinir les
méthodes mutables

ENSAM 2020-2021- T.HAJJI- 363


Methodes à implanter
Pour
– AbstractCollection/AbstractSet
● size() et iterator()
– AbstractMap

entrySet()
– Attention get sera en O(n) !
– AbstractList
● size() et get(int)
– AbstractSequentialList
● size() et listIterator(int)

ENSAM 2020-2021- T.HAJJI- 364


Exemple
Renvoie une liste dont chaque élement est calculé par la fonction de projection (mapper) à partir
de l'élement dans la liste initiale

public static <T,U> List<U> map(List<T> list, Function<? super T, ? extends U> mapper) {
class MappedList extends List<U> implements RandomAccess {
@Override
public int size() {
return list.size();
}
@Override
public U get(int index) {
return mapper.apply(list.get(index));
}
}
return new MappedList();
}

ENSAM 2020-2021- T.HAJJI- 365


ArrayList
Tableau dynamique (qui s'agrandit tout seul)
facteur à 1.5 par défaut
Complexité
– Insertion à la fin en 0(1) amortie
– Insertion en début ou au millieu en O(n)
– Accès au index-ième élement en O(1)
Parcours:
– Avec un itérateur O(n)
– Avec un index, O(n) mais plus rapide

ENSAM 2020-2021- T.HAJJI- 366


LinkedList
Liste doublement chaînée
Complexité
–Insertion au début ou fin en O(1)
–Insertion au millieu
● avec add O(n)

avec listIterator.add 0(1)
– Accès au index-ième élement en O(n)
Parcours:
– Avec un itérateur O(n)
– Avec un index, O(n2) !!!
ENSAM 2020-2021- T.HAJJI- 367
ArrayDeque
Buffer circulaire dynamique à deux pointeurs
–Taille en puissance de 2

Complexité
–Insertion/suppression au début/à la fin en 0(1) amortie

Parcours:
–Avec un itérateur O(n)

ENSAM 2020-2021- T.HAJJI- 368


HashMap
Table de hachage dynamique avec liste chainée ou arbre
pour gérer les collisions
–Agrandissement si plein a plus de 75%
–taille en puissance de 2
–Protection DDOS
Complexité
–Insertion/suppression/accès 0(1) amortie
Parcours:
–Avec un itérateur O(n)
sur le résultat de keySet(), entrySet() ou values()
ENSAM 2020-2021- T.HAJJI- 369
WeakHashMap
Table de hachage dynamique
– Les clés sont stockées avec des références faibles
(pas compté par le GC)
● Bug: marche pas si la clé est référencé par la valeur (pas
d'ephemeron :( )

peut être utilisé comme un cache qui se vide


automatiquement si il n'y a plus assez de mémoire
–Attention, à ne pas mettre trop d'élément !
–Attention, le cache doit se recréer incrémentalement !

ENSAM 2020-2021- T.HAJJI- 370


IdentityHashMap
Table de hachage dynamique fermée
–Utilise== et System.identityHashCode à la place de equals et
hashCode
–Gestion des collisions l'intérieur de la table

–Utiliseun seul tableau avec les clés et les valeurs à des index
consécutif

Même complexité que HashMap


–Plus lent si beaucoup d'élement
–Consomme moins de mémoire si peu d'élement
ENSAM 2020-2021- T.HAJJI- 371
TreeMap
Arbre rouge/noir, maintient l'ensemble des clés triés
–Auto-équilibrage donc hauteur en ln(n)
Complexité
–Insertion/suppression/accès 0(ln(n)) amortie
Parcours:
–Avec un itérateur O(n)
sur le résultat de keySet(), entrySet() ou values()

ENSAM 2020-2021- T.HAJJI- 372


EnumSet
Set spécialisée si les élements viennent tous du
même enum
–ordinal() est une fonction de hash parfait
–Deux implantations
Si enum.values().length <=64, utilise 1 long (regular) sinon utilise
un tableau de long (jumbo)

Même complexité que HashSet mais


représentation en mémoire très compacte

ENSAM 2020-2021- T.HAJJI- 373


EnumMap
Map spécialisée si les clés viennent tous du même
enum, utilise un tableau de taille fixe.
– ordinal() est une fonction de hash parfait

Même complexité que HashMap mais


représentation en mémoire très compacte

ENSAM 2020-2021- T.HAJJI- 374


Java MySQL

• ODBC JAVA MySQL


• Chargement du driver ,
• La classe Connexion,
• La classe DriverManager,
• La classe Statement et PreparStatment
• La classe ResultSet
• Le bloc static dans une classe

ENSAM 2020-2021- T.HAJJI- 375


Le problème de l’accès aux données sans
JDBC
• Java est un excellent candidat pour le
développement d’applications de bases de
données:
– robuste et sécurisé
– facile à comprendre
– automatiquement téléchargeable par le réseau
• mais avant JDBC, il était difficile d’accéder à
des bases de données SQL depuis Java :
– obligé d’utiliser des API natives comme ODBC
376

ENSAM 2020-2021- T.HAJJI- 376


Objectifs de JDBC

 Permettre aux programmeurs Java d’écrire un


code indépendant de la base de données et du
moyen de connectivité utilisé
 Réalisé par l’API JDBC :
 une interface uniforme permettant un accès
homogène aux SGBD
 simple à mettre en œuvre
 indépendant de la SGBD cible
 supportant les fonctionnalités de base du langage
SQL 377

ENSAM 2020-2021- T.HAJJI- 377


Avantages

Liés a Java :
• Portabilité sur de nombreux O.S. et sur de
nombreuses SGBDR (Oracle, Informix,
Sybase, ..)
• Uniformité du langage de description des
applications, des applets et des accès aux bases
de données
• Liberté totale vis a vis des constructeurs
378

ENSAM 2020-2021- T.HAJJI- 378


Qu’est ce que JDBC ?

• Java DataBase Connectivity


• API Java adaptée à la connexion avec les bases de
données relationnelles (SGBDR)
• Fournit un ensemble de classes et d’interfaces
permettant l’utilisation sur le réseau d’un ou
plusieurs SGBDR à partir d’un programme Java.

379

ENSAM 2020-2021- T.HAJJI- 379


L'architecture JDBC standard

• Tout programme comporte 3 composants :


– Le code de l'application (ou de l'applet)
• Les requêtes doivent être au standard JDBC

– Le JDBC Driver Manager


• Fourni par SUN
• Lien entre l'application et les pilotes (ou drivers) JDBC

– Le driver JDBC
• Fourni par le fournisseur de la base ou autre
• Adapté à la BD
• Convertit les requêtes JDBC en requêtes propres à la base

380

ENSAM 2020-2021- T.HAJJI- 380


Architecture JDBC

381

ENSAM 2020-2021- T.HAJJI- 381


Les types de pilotes JDBC

• 4 types de drivers (taxonomie de JavaSoft) :


– Type I : JDBC-ODBC bridge driver
– Type II : Native-API, partly-Java driver
– Type III : Net-protocol, all-Java driver
– Type IV : Native-protocol, all-Java driver
• Tous les drivers :
– http://www.javasoft.com/products/jdbc/drivers.html

382

ENSAM 2020-2021- T.HAJJI- 382


Les types de pilotes JDBC
• Type 1 ( JDBC-ODBC bridge ) : le pont JDBC-ODBC qui s'utilise avec
ODBC et un pilote ODBC spécifique pour la base à accéder. C'est la
solution idéale pour des développements avec exécution sous Windows
d'une application locale.
• inconvénients :
– la multiplication du nombre de couches rend complexe l'architecture
(bien que transparent pour le développeur) et détériore un peu les
performances
– lors du déploiement, ODBC et son pilote doivent être installé sur
tous les postes ou l'application va fonctionner.
– la partie native (ODBC et son pilote) rend l'application moins
portable et dépendant d'une plateforme.
383

ENSAM 2020-2021- T.HAJJI- 383


Les types de pilotes JDBC

• Type 2 ( Driver d’API natif) :


– fait appel à des fonctions natives (non Java) de l
’API du SGBDR
• gère des appels C/C++ directement avec la base

– fourni par les éditeurs de SGBD et généralement


payant
– ne convient pas aux applets (sécurité)
• interdiction de charger du code natif dans la mémoire vive de la
plateforme d’exécution
384

ENSAM 2020-2021- T.HAJJI- 384


Les types de pilotes JDBC
• Type 3 : un driver écrit en Java utilisant le protocole
natif de la base de données.
– Ce type de driver utilise un protocole réseau propriétaire
spécifique à une base de données.
– Un serveur dédié reçoit les messages par ce protocole et
dialogue directement avec la base de données.
– Ce type de driver peut être facilement utilisé par une
applet mais dans ce cas le serveur intermédiaire doit
obligatoirement être installé sur la machine contenant le
serveur web.
385

ENSAM 2020-2021- T.HAJJI- 385


Les types de pilotes JDBC

• Type 4 : un driver Java natif


– Ce type de driver, écrit en java, appelle directement le
SGBD par le réseau. Ils sont fournis par l'éditeur de la
base de données.
– Avantage : tout le code est chargé sur le poste client
sous forme de classes java.
– Inconvénient : La base de données reste sur le serveur
d’applets.

386

ENSAM 2020-2021- T.HAJJI- 386


Modèles de connexion en Java

2-tiers : 2 entités interviennent


 une application Java ou une applet
 le SGBDR

Modèle 3-tiers : 3 entités interviennent


 une application Java ou une applet
 un serveur middleware installé sur le réseau
 le SGBDR

387

ENSAM 2020-2021- T.HAJJI- 387


Modèle 2-tiers
Principe :
 l’application (ou l’applet) cliente utilise JDBC pour parler
directement avec le SGBD qui gère la base de données
Avantages :
 simple à mettre en œuvre
 bon choix pour des applications clientes peu évoluées, à
livrer rapidement et n’exigeant que peu de maintenance
 Inconvénients :
 dépendance forte entre le client et la structure du SGBDR
modification du client si l’environnement serveur change
 tendance à avoir des clients « graisseux »
tout le traitement est du côté client
388

ENSAM 2020-2021- T.HAJJI- 388


Architecture 2-tiers

389

ENSAM 2020-2021- T.HAJJI- 389


Modèle 3-tiers
 Principes :
 le serveur middleware est l’interlocuteur direct du code Java
client; c’est lui qui échange des données avec le SGBDR
 pas forcément écrit en Java
 si c’est le cas : utilise souvent JDBC pour accéder au SGBDR
 Avantages:
 le middleware peut ajouter un niveau de sécurité
 plusieurs supports pour les échanges avec le client :
sockets, RMI Java, CORBA, …
 applets : le SGBDR peut se trouver sur une autre machine:
mais serveur Web et middleware au même endroit
 facilite l’utilisation de clients « légers » 390

ENSAM 2020-2021- T.HAJJI- 390


Modèle 3-tiers

391

ENSAM 2020-2021- T.HAJJI- 391


Scénarios d’utilisation

• Scénario 1 :
– architecture 2-tiers avec une application Java

392

ENSAM 2020-2021- T.HAJJI- 392


Scénarios d’utilisation

• Scénario 2 :
– architecture 2-tiers avec une applet Java

393

ENSAM 2020-2021- T.HAJJI- 393


Scénarios d’utilisation

• Scénario 3 :
– architecture 3-tiers et applet/application Java

394

ENSAM 2020-2021- T.HAJJI- 394


L’API JDBC

Est fournie par le package java(x).sql


• permet de formuler et gérer les requêtes aux bases
de données relationnelles
• supporte le standard « SQL-3 Entry Level »
• Classes/interfaces définissant les objets
nécessaires:
– à la connexion à une base éloignée
– et à la création et exécution de requêtes SQL
395

ENSAM 2020-2021- T.HAJJI- 395


L’API JDBC

Disponible en plusieurs versions


 JDBC 1 :
Livrée avec JDK 1.1
Tout se trouve dans le package java.sql
 JDBC 2 :
2 packages
J2SE contient java.sql (SDK 1.2+)
J2EE contient javax.sql
 JDBC 3 :
Avec J2SE, SDK 1.4+
Le cours est basé sur JDBC 1 et 2
396

ENSAM 2020-2021- T.HAJJI- 396


Les classes de l'API JDBC

• Les classes de java.sql :


– Statement
– CallableStatement, PreparedStatement
– DatabaseMetaData, ResultSetMetaData
– ResultSet,
– Connection
– Driver
• De javax.sql :
– RowSet
– Datasource 397

ENSAM 2020-2021- T.HAJJI- 397


LES CLASSES DE L'API JDBC

• Toutes les classes de JDBC sont dans le


package java.sql

Classe Role

DriverManager Charge et configure le driver de la base de données.


Connection Réalise la connexion et l'authentification à la base de
données.
Statement ( et Contient la requête SQL et la transmet à la base de données.
PreparedStatement )
ResultSet Permet de parcourir les informations retournées par la base de
données
dans le cas d'une sélection de données 398

ENSAM 2020-2021- T.HAJJI- 398


La connexion à une base de données

1. Chargement d’un pilote JDBC


2. Définition de l’URL de connexion
3. Etablissement de la connexion
4. Création d’une instruction
5. Exécution de la requête
6. Traitement des résultats
7. Fermeture de la connexion
399

ENSAM 2020-2021- T.HAJJI- 399


Chargement d’un pilote JDBC
• Pour se connecter à une base de données via ODBC, il faut tout d'abord
charger le pilote JDBC-ODBC qui fait le lien entre les deux.
• L’utilisation de la méthode Class.forName() peut lever une exception
de type ClassNotFoundException, il convient donc de placer le
chargement du pilote dans un bloc sécurisé.
• Exemple :

try {
Class.forName("oracle.jdbc.driver.OracleDriver");
}
catch(ClassNotFoundException e) {
System.err.println("Erreur de chargement du driver :" + e);
}

400

ENSAM 2020-2021- T.HAJJI- 400


Définition de l’URL de connexion

Afin de localiser votre serveur ou votre base de


données, il est indispensable de spécifier une
adresse sous forme d’URL de type « jdbc: ».
Pour une connexion à une base de données en
utilisant un driver JDBC, l’URL se compose
comme suit: jdbc:<sous-protocole>:<nom-
BD>?param=valeur, ...

Exemple:
String url=jdbc:odbc:Mabase

ou String jdbcUri =


"jdbc:oracle:thin:@localhost:1521:orcl"; 401

ENSAM 2020-2021- T.HAJJI- 401


Etablissement de la connexion
• La classe DriverManager dispose d’une méthode statique permettant
d’obtenir une connexion à l’URL, la méthode getConnection() qui
retourne un objet de type Connexion.
• Cette méthode peut, si la connexion échoue ou si aucun pilote ne prend en
charge l’URL spécifiée, une exception de type SQLException.
• Exemple :

Import java.sql.* ;
...
try {
Connection con = DriverManager.getConnection(url,userId,password) ;
}
catch(SQLException sqle) {
System.err.println("Erreur lors de la connexion : " + sqle) ;
}

402

ENSAM 2020-2021- T.HAJJI- 402


Les transactions
• Une transaction est un ensemble de traitements qui sont regroupés pour être
validés ou invalidés simultanément
• Par défaut une nouvelle connexion fonctionne en validation automatique «
auto-commit ».
• Chaque opération est validée individuellement.
• Pour gérer des transactions il faut donc modifier l’état par défaut.
• Les transactions seront ensuite validées ou invalidées par l’appel des
méthodes commit() ou rollback().

public abstract void setAutoCommit(boolean autoCommit) throws


SQLException

403

ENSAM 2020-2021- T.HAJJI- 403


Création d’une instruction.

• Afin d’accéder ou de modifier les informations


contenues dans la base de données, il convient
d’utiliser un objet de type Statement.
• Une instance de cet objet est retournée par la
méthode
Statement statement = con.createStatement() ;
Connexion.createStatement() comme
ceci :

404

• 3 types de Statement :
ENSAM 2020-2021- T.HAJJI- 404
– Statement : requêtes statiques simples
Exécution d’une requête

Pour une requête de type interrogation (SELECT),


la méthode à utiliser de la classe Statement est
executeQuery().
 Retourne un ResultSet (tuples résultants)
String query = "SELECT * FROM Employés";
ResultSet resultset = statement.executeQuery(query);

Pour des traitements de mise à jour, il faut utiliser


la méthode executeUpdate().
String query = "DELETE FROM Employés WHERE Région = ‘WA’";
 Retournent un entier (nombre de tuples traités)
int result = statement.executeUpdate(query) ;
405

ENSAM 2020-2021- T.HAJJI- 405


Traitement du résultat
• Le résultat d'une requête d'interrogation est renvoyé dans un objet de la
classe ResultSet par la méthode executeQuery().
• En ce qui concerne la numérotation des colonnes, elle ne commence pas à 0
comme pour les tableaux JAVA, mais à 1.
• lors de l’exécution de la requête, l’objet ResultSet ne semble pas
positionné sur le premier enregistrement mais avant, dans une zone que l’on
nomme le GAP.
• L’objet ResultSet dispose aussi d’un certain nombre de méthodes
permettant de naviguer d’un enregistrement à un autre.

while(resultset.next()) {
System.out.println(resultset.getString(1)) ;
} 406

ENSAM 2020-2021- T.HAJJI- 406


la classe ResultSet
Les principales méthodes pour obtenir des données sont :
Méthode Rôle
getInt(int) retourne le contenu de la colonne dont le numéro est passé en paramètre sous forme
d'entier.
getInt(String) retourne le contenu de la colonne dont le nom est passé en paramètre sous forme
d'entier.
getFloat(int) retourne le contenu de la colonne dont le numéro est passé en paramètre sous forme
de nombre flottant.
getFloat(String)

getDate(int) retourne le contenu de la colonne dont le numéro est passé en paramètre sous forme
de date.
getDate(String)

next() se déplace sur le prochain enregistrement : retourne false si la fin est atteinte
Close() ferme le ResultSet
407
getMetaData() retourne un objet ResultSetMetaData associé au ResultSet.

ENSAM 2020-2021- T.HAJJI- 407


Fermeture de la connexion

Pour terminer proprement un traitement, il faut


fermer les différents espaces ouverts
 sinon le garbage collector s’en occupera mais moins
efficace
Chaque objet possède une méthode close() :
 resultset.close();
 statement.close();
 connection.close();

408

ENSAM 2020-2021- T.HAJJI- 408


Exemple de consultation
import java.sql.*;
public class AffichageBaseDeDonnees {
public static void main(String args[]) {
String n,p,uid;
String url = "jdbc:odbc:BDMUS";
Statement req = null;
Connection con=null;
ResultSet res;
try { Class.forName("Sun.jdbc.odbc.JdbcOdbcDriver");}
catch (Exception e) {
System.out.println("Erreur de chargement du pilote JDBC/ODBD.");
}
try { con = DriverManager.getConnection (url);
req = con.createStatement();
}
catch (Exception e) {
System.err.println("Erreur de connexion à jdbc:odbc:BDID"); }
try { System.out.println("\n >> résultat obtenu : \n");
res= req.executeQuery("select * from identite");
while (res.next()) {
uid = res.getString("id_user");
n = res.getString("Nom");
p = res.getString("Prenom");
System.out.println("\n" + uid + " - " + n + " - " + p + "\n");
}
}
catch (Exception e) { e.printStackTrace(); }
finally { try {con.close();}
catch(SQLException e){e.printStackTrace();} 409
} // fin finally
}//Fin de la fonction main
}//Fin
ENSAMdu programme
2020-2021- T.HAJJI- 409
Exemple de remplissage
import java.sql.*;
import java.io.*;
public class RemplBaseDeDonnees {
public static void main(String args[]) {
DataInputStream din = new DataInputStream(System.in);
String id,N,P,str="";
String url = "jdbc:odbc:BDMUS";
Connection con=null;
PreparedStatement req = null;
try { con = DriverManager.getConnection(url);}
catch (Exception e) { System.err.println("Erreur de connexion à jdbc:odbc:BDID"); }
try { System.out.print("\n\n Debut d'enregistrement : \n");
System.out.print("\nUser_id = ");
id = din.readLine();
System.out.print("\nNom : ");
N = din.readLine();
System.out.print("\nPrenom : ");
P = din.readLine();
str="'"+id+"','"+N+"','"+P+"'";
str="INSERT INTO identite(id_user,Nom,Prenom) values ("+str+")";
req=con.prepareStatement(str);
req.executeUpdate();
}
catch (Exception e) { e.printStackTrace(); }
finally { try {con.close();}
catch(SQLException e) {e.printStackTrace();}
}
}//Fin de la méthode main 410
}//Fin du programme

ENSAM 2020-2021- T.HAJJI- 410


Exemple de suppression

import java.sql.*;
import java.io.*;
public class SuppressionBaseDeDonnees {
public static void main(String args[]) {
DataInputStream din = new DataInputStream(System.in);
String url = "jdbc:odbc:BDMUS",N;
PreparedStatement req=null;
Connection con=null;
try { con = DriverManager.getConnection (url);}
catch (Exception e) { System.err.println("Erreur de connexion à jdbc:odbc:BDID");}
try {
System.out.print("\nNom : ");
N = din.readLine();
req=con.prepareStatement("delete from identite where Nom='"+N+"'");
req.executeUpdate();

}
catch (Exception e) { e.printStackTrace(); }
finally { try {con.close();}
catch(SQLException e) {e.printStackTrace();}
}
} //Fin de la methode main
}//Fin du programme
411

ENSAM 2020-2021- T.HAJJI- 411


Exemple plus pratique

import java.sql.*;
public class Connexion {
private Connection connexion;
private Statement instruction;
protected ResultSet résultat;
String DB="mabase";
public Connexion() { //constructeur
try {
Class.forName("com.mysql.jdbc.Driver");
connexion = DriverManager.getConnection("jdbc:mysql://localhost:3333/mabase",
"root", "");
instruction = connexion.createStatement();
}
catch (ClassNotFoundException ex) {
System.err.println("Problème de pilote");
}
catch (SQLException ex) {
System.err.println("Base de données non trouvée ou requête incorrecte");
}
}
public void lire(String requête) { //--- }
public void miseAJour(String requête) { //--- }
public boolean suivant() { //--- }
} 412

ENSAM 2020-2021- T.HAJJI- 412


Exemple plus pratique
import java.sql.SQLException;

public class ListePersonne extends Connexion {


public ListePersonne(int id) {
lire("SELECT * FROM personne WHERE id="+id+"");

}
public ListePersonne() {
lire("SELECT * FROM personne");
}
public String nom() {
try {
return résultat.getString("nom");
} catch (SQLException ex) {
return "";
}
}
public String prenom() { //-- }

public String email() { //-- }

public int id() { //-- } ListePersonne


}
public ListePersonne()
public ListePersonne(int id)
public String nom()
public String prenom() 413
public String email()
public int id()
ENSAM 2020-2021- T.HAJJI- 413
Exemple plus pratique
public class Main {

public static void main(String[] args) {


ListePersonne LP = new ListePersonne();
while (LP.suivant()) {
System.out.println(LP.prenom());
System.out.println(LP.nom());
System.out.println(LP.email());

}
LP.arrêt();
}
}

ListePersonne
public ListePersonne()
public ListePersonne(int id)
public String nom()
public String prenom() 414
public String email()
public int id()
ENSAM 2020-2021- T.HAJJI- 414
PreparedStatement

 Lors de l'envoi d'une requête pour exécution 4 étapes doivent


être faites :
 analyse de la requête
 compilation de la requête
 optimisation de la requête
 exécution de la requête
et ceci même si cette requête est la même que la précédente!!
Or les 3 premières étapes ont déjà été effectuées dans ce cas.
 Les bases de données définissent la notion de requête
préparée, requête où les 3 premières étapes ne sont
effectuées qu'une seule fois.
 Modéliser cette notion: l'interface PreparedStatement
 Interface dérive de l'interface Statement.

415

ENSAM 2020-2021- T.HAJJI- 415


PreparedStatement
 On ne peut pas avec un Statement construire des requêtes paramétrées.
 Il faut pour cela utiliser un PreparedStatement.
 Syntaxe:

PreparedStatement pSmt =
conX.prepareStatement("SELECT * FROM Livres" );
ResultSet rs = pSmt.executeQuery();
 Exemple :

PreparedStatement pSmt = conX.prepareStatement("SELECT


nom FROM Personnes WHERE age > ? AND adresse = ?" );
pSmt.setInt(1, 22); setType(numéroDeLArgument, valeur)
pSmt.setString(2, "Turin");
ResultSet rs = smt.executeQuery();
416

ENSAM 2020-2021- T.HAJJI- 416


CallableStatement

L'interface CallableStatement définit les


méthodes pour un objet qui va permettre
d'appeler une procédure stockée.
Cette interface hérite de l'interface
PreparedStatement.
Un objet qui implémente l'interface
CallableStatement est obtenu en utilisant
la méthode prepareCall() d'un objet de type
Connection. 417

ENSAM 2020-2021- T.HAJJI- 417


Exécution
 On lance l’exécution d’une procédure stockée à l'aide de la syntaxe :
 {call nom_procedure_stockees} : cette forme la plus simple
permet l'appel d'une procédure stockée sans paramètre ni valeur de retour
 {call nom_procedure_stockees(?, ?, ...)} : cette forme
permet l'appel d'une procédure stockée avec des paramètres
 {? = call nom_procedure_stockees(?, ?, ...)} : cette
forme permet l'appel d'une procédure stockée avec des paramètre et une
valeur de retour·

418

ENSAM 2020-2021- T.HAJJI- 418


Exécution
Pour exécuter la requête, l'interface
PreparedStatement propose deux méthodes:
 executeQuery() : cette méthode permet d'exécuter
une requête de type interrogation et renvoie un objet de
type ResultSet qui contient les données issues de
l'exécution de la requête·
 executeUpdate() : cette méthode permet d'exécuter
une requête de type mise à jour et renvoie un entier qui
contient le nombre d'occurrences impactées par la mise à
jour.

419

ENSAM 2020-2021- T.HAJJI- 419


JDBC 2.0
• La version 2.0 de l'API JDBC a été intégrée au JDK 1.2. Cette
nouvelle version apporte plusieurs fonctionnalités très intéressantes
dont les principales sont :
– support du parcours dans les deux sens des résultats.
– support de la mise à jour des résultats.
– possibilité de faire des mises à jour de masse (Batch Updates)
– prise en compte des champs définis par SQL-3 dont BLOB
(BinaryLargeOBject ) et CLOB (CharacterLargeOBject)
• L'API JDBC 2.0 est séparée en deux parties :
– la partie principale (core API) contient les classes et interfaces nécessaires à
l'utilisation de bases de données : elles sont regroupées dans le package
java.sql·
– la seconde partie est une extension utilisée dans J2EE qui permet de gérer les
transactions distribuées, les pools de connection, la connection avec un objet
DataSource ... Les classes et interfaces sont regroupées dans le package 420
javax.sql·
ENSAM 2020-2021- T.HAJJI- 420
JDBC 2.0
Méthode Rôle
boolean isAfterLast() renvoie un booleen qui indique si la position courante du curseur se trouve
après la dernière ligne.
boolean isFirst() renvoie un booleen qui indique si le curseur est positionné sur la première
ligne
boolean isLast() renvoie un booleen qui indique si le curseur est positionné sur la dernière
ligne
boolean first() déplace le curseur sur la première ligne

boolean last() déplace le curseur sur la dernière ligne

boolean absolute() déplace le curseur sur la ligne dont le numéro est fournie en paramètre à partir
du début si il est positif et à partir de la fin si il est négatif. 1 déplace sur la
première ligne, 1 sur la dernière, -2 sur l'avant dernière ...
boolean relative(int) déplace le curseur du nombre de lignes fourni en paramètre par rapport à la
position courante du curseur. Le paramètre doit être négatif pour se déplacer
vers le début et positif pur se déplacer vers la fin. Avant l'appel de cette
méthode, il faut obligatoirement que le curseur soit positionné sur une ligne.
boolean previous() déplace le curseur sur la ligne précédente. Le booleen indique si la première
occurrence est dépassée.
421

ENSAM 2020-2021- T.HAJJI- 421


JDBC 2.0

void afterLast()
 déplace le curseur après la dernière ligne
void beforeFirst()
 déplace le curseur avant la première ligne
int getRow()
 renvoie le numéro de la ligne courante

422

ENSAM 2020-2021- T.HAJJI- 422


JDBC 2.0
Méthode Rôle
 updateXXX(String, XXX) permet de mettre à jour la colonne dont le
nom est fourni en paramètre. Le type Java
de cette colonne est XXX
 updateXXX(int, XXX) permet de mettre à jour la colonne dont
l'index est fourni en paramètre. Le type
Java de cette colonne est XXX
 updateRow() permet d'actualiser les modifications
réalisées avec des appels à updateXXX()
 boolean rowsUpdated() indique si la ligne courante a été modifiée
 deleteRow() supprime la ligne courante
 rowDeleted() indique si la ligne courante est supprimée
 moveToInsertRow() permet de créer une nouvelle ligne dans
l'ensemble de résultat 423

 inserRow()
ENSAM 2020-2021- T.HAJJI- 423
permet de valider la création de la ligne
Accès aux méta-données
La méthode getMetaData () permet d’obtenir
des informations sur les types de données du
ResultSet
 elle renvoie des ResultSetMetaData
 on peut connaître entre autres :
 le nombre de colonne : getColumnCount()
 le nom d’une colonne : getColumnName(int
col)
 le nom de la table : getTableName(int col)
 si un NULL SQL peut être stocké dans une colonne :
isNullable() 424

ENSAM 2020-2021- T.HAJJI- 424


ResultSetMetaData

ResultSet rs = stmt.executeQuery("SELECT * FROM emp");


ResultSetMetaData rsmd = rs.getMetatData();

int nbColonnes = rsmd.getColumnCount();


for(int i = 1; i <= nbColonnes; i++) {
// colonnes numerotées à partir de 1 (et non 0)
String nomCol = rsmd.getColumnName(i);

425

ENSAM 2020-2021- T.HAJJI- 425


DatabaseMetaData

• Pour récupérer des informations sur la base de


données elle-même, utiliser la méthode
getMetaData() de l’objet Connection
– dépend du SGBD avec lequel on travaille
– elle renvoie des DatabaseMetaData
– on peut connaître entre autres :
• getDriverVersion(), getDriverName(),
• getDatabaseProductName(), getDatabaseProductVersion()
• les tables de la base : getTables()
• le nom de l’utilisateur : getUserName()
426

ENSAM 2020-2021- T.HAJJI- 426


Le composant RowSet

A démarré avec JDBC 2


 Interfacé vers un containeur pour tabuler les données
 Souvent associé avec un ResultSet
 Peut être n'importe quelle donnée, tableau, fichier à
plat, etc.
Étend l'interface de ResultSet
 Contient un ensemble complet de propriétés
 Supporte les interactions basées sur les évènements
427

ENSAM 2020-2021- T.HAJJI- 427


Le composant RowSet (2)

Il a la possibilité de se remplir lui-même avec des


données
 Définition de l'emplacement de la base de données dans
une propriété principale
 Peut aussi être rempli à partir d'un ResultSet
existant

428

ENSAM 2020-2021- T.HAJJI- 428


RowSetReader et RowSetWriter

Chaque classe qui implémente une RowSet


dispose d'une lecture et d'une écriture associées :
 La lecture extrait les données à partir de la source de
données pour remplir le RowSet : appliquer l'interface
RowsetReader
 L'écriture extrait les données du RowSet et les envoie
dans la source de données : appliquer RowSetWriter

429

ENSAM 2020-2021- T.HAJJI- 429


Types de RowSet
Les types définis par les fournisseurs :
• CachedRowSet :
– Déconnecte le RowSet qui stocke ces données
dans la mémoire
– Ne convient pas à des données volumineuses
– Idéal pour les client java légers ou les PDA
• JDBCRowSet :
– Sert de fin emballage autour du ResultSet
– Utilise un driver JDBC
• WebRowSet : 430

– Connecte le RowSet qui utilise le protocole HTTP


ENSAM 2020-2021- T.HAJJI- 430
Connexion/déconnexion du RowSet

Les RowSet peuvent être utilisés de la même


manière que les ResultSet standards
 Peuvent être reliés à une source de données en
permanence
Peuvent aussi être déconnectés de la source de
données
 Se comportent comme source de données pour le
client (données cachées)
 Peuvent être séralisés et transmis à travers le réseau 431
 Utile pour les clients légers (PDAs, les périphériques non connectés)
ENSAM 2020-2021- T.HAJJI- 431
Programmation orientée objet

Les threads

ENSAM 2020-2021- T.HAJJI- 432


Muti-tâches

• Multi-tâches : exécution de plusieurs processus


simultanément.
– Un processus est un programme en cours d'exécution.
– Le système d’exploitation distribue le temps CPU entre les
processus
• Un processus peut être dans différents états.
– En exécution (running) : il utilise le processeur
– Prêt : le processus est prêt à s'exécuter, mais n'a pas le processeur
(occupé par un autre processus en exécution)
– Bloqué

ENSAM 2020-2021- T.HAJJI- 433


433
Parallélisme

• Parallélisme : pouvoir faire exécuter plusieurs tâches à


un ordinateur avec plusieurs processeurs.
• Si l’ordinateur possède moins de processeurs que de
processus à exécuter :
– division du temps d’utilisation du processeur en tranches de
temps (time slice en anglais)
– attribution des tranches de temps à chacune des tâches de
façon telle qu’on ait l’impression que les tâches se d&roulent
en parallèle.
– on parle de pseudo-parallélisme
• Les systèmes d’exploitation modernes gèrent le muti-
tâches et le parallélisme
ENSAM 2020-2021- T.HAJJI- 434
434
Qu’est-ce qu’un Thread ?
• les threads sont différents des processus :
– ils partagent code, données et ressources : « processus légers »
– mais peuvent disposer de leurs propres données.
– ils peuvent s’exécuter en "parallèle"
• 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 : paralèllisme
– simplicité d’utilisation : c’est un objet Java (java.lang)

ENSAM 2020-2021- T.HAJJI- 435


435
Création

• La classe java.lang.Thread permet de créer de nouveaux


threads
• Un thread doit implémenter obligatoirement l’interface
Runnable
– le code exécuté se situe dans sa méthode run()
• 2 méthodes pour créer un Thread :
– 1) une classe qui dérive de java.lang.Thread
• java.lang.Thread implémente Runnable
• il faut redéfinir la méthode run()
– 2) une classe qui implémente l’interface Runnable
• il faut implémenter la méthode run()

ENSAM 2020-2021- T.HAJJI- 436


436
Methode 1 : Sous-classer Thread

class Proc1 extends Thread {


Proc1() {...} // Le constructeur
...
public void run() {
... // Ici ce que fait le processus : boucle infinie
}
}
...
Proc1 p1 = new Proc1(); // Création du processus p1
p1.start(); // Demarre le processus et execute p1.run()

ENSAM 2020-2021- T.HAJJI- 437


437
Méthode 2 :
une classe qui implémente Runnable
class Proc2 implements Runnable {
Proc2() { ...} // Constructeur
...
public void run() {
... // Ici ce que fait le processus
}
}
...
Proc2 p = new Proc2();
Thread p2 = new Thread(p);
...
p2.start(); // Démarre un processus qui execute p.run()

ENSAM 2020-2021- T.HAJJI- 438


438
Quelle solution choisir ?
• Méthode 1 : sous-classer Thread
– lorsqu’on désire paralléliser une classe qui n’hérite pas déjà d’une autre
classe (attention : héritage simple)
– cas des applications autonomes

• Méthode 2 : implémenter Runnable


– lorsqu’une super-classe est imposée
– cas des applets
public class MyThreadApplet
extends Applet implements Runnable {}

• Distinguer la méthode run (qui est le code exécuté par l’activité) et la méthode
start (méthode de la classe Thread qui rend l’activité exécutable) ;
• Dans la première méthode de création, attention à définir la méthode run avec
strictement le prototype indiqué (il faut redéfinir Thread.run et non pas la
surcharger).

ENSAM 2020-2021- T.HAJJI- 439


439
Le cycle de vie

ENSAM 2020-2021- T.HAJJI- 440


440
Les états d’un thread

• Créé :
- comme n’importe quel objet Java
- ... mais n’est pas encore actif

- Actif :
- après la création, il est activé par start() qui lance run().
- il est alors ajouté dans la liste des threads actifs pour être exécuté
par l’OS en temps partagé
- peut revenir dans cet état après un resume() ou un notify()

ENSAM 2020-2021- T.HAJJI- 441


441
Exemple

class ThreadCompteur extends Thread {


int no_fin;
ThreadCompteur (int fin) {no_fin = fin;} // Constructeur
// On redéfinit la méthode run()
public void run () {
for (int i=1; i<=no_fin ; i++) {
System.out.println(this.getName()+":"+i);} }

public static void main (String args[]) {


// On instancie les threads
ThreadCompteur cp1 = new ThreadCompteur (100);
ThreadCompteur cp2 = new ThreadCompteur (50);
cp1.start();
cp2.start();
} }

ENSAM 2020-2021- T.HAJJI- 442


442
Les états d’un Thread (suite)

• Endormi ou bloqué :
– après sleep() : endormi pendant un intervalle de temps (ms)
– suspend() endort le Thread mais resume() le réactive
– une entrée/sortie bloquante (ouverture de fichier, entrée clavier)
endort et réveille un Thread
• Mort :
– si stop() est appelé explicitement
– quand run() a terminé son exécution

ENSAM 2020-2021- T.HAJJI- 443


443
Exemple d’utilisation de sleep

class ThreadCompteur extends Thread {


int no_fin; int attente;
ThreadCompteur (int fin,int att) {
no_fin = fin; attente=att;}
// On redéfinit la méthode run()
public void run () {
for (int i=1; i<=no_fin ; i++) {
System.out.println(this.getName()+":"+i);
try {sleep(attente);}
catch(InterruptedException e) {};}
}
public static void main (String args[]) {
// On instancie les threads
ThreadCompteur cp1 = new ThreadCompteur (100,100);
ThreadCompteur cp2 = new ThreadCompteur (50,200);
cp1.start();
cp2.start();
} }

ENSAM 2020-2021- T.HAJJI- 444


444
Les priorités

• Principes :
– Java permet de modifier les priorités (niveaux absolus) desThreads par la
méthode setPriority()
– Par défaut, chaque nouveau Thread a la même priorité que le Thread qui l’a
crée
– Rappel : seuls les Threads actifs peuvent être exécutés et donc accéder au
CPU
– La JVM choisit d’exécuter le Thread actif qui a la plus haute priorité :
priority-based scheduling
– si plusieurs Threads ont la même priorité, la JVM répartit équitablement le
temps CPU (time slicing) entre tous : round-robin scheduling

ENSAM 2020-2021- T.HAJJI- 445


445
Les priorités (suite)

• Les méthodes :
– setPriority(int) : fixe la priorité du receveur.
• le paramètre doit appartenir à :
[MIN_PRIORITY, MAX_PRIORITY]
• sinon IllegalArgumentException est levée
– int getPriority() : pour connaître la priorité d’un Thread
NORM_PRIORITY : donne le niveau de priorité
"normal"

ENSAM 2020-2021- T.HAJJI- 446


446
La gestion du CPU

• Time-slicing (ou round-robin scheduling) :


– La JVM répartit de manière
équitable le CPU entre
tous les threads de même priorité.
Ils s’exécutent en "parallèle".
• Préemption (ou priority-based scheduling) :
– Le premier thread du groupe des threads à priorité égale monopolise le
CPU. Il peut le céder :
• involontairement : sur entrée/sortie
• volontairement : appel à la méthode statique yield()
Attention : ne permet pas à un thread de priorité inférieure de s’exécuter
(seulement de priorité égale)
• implicitement en passant à l’état endormi (wait(), sleep() ou suspend())

ENSAM 2020-2021- T.HAJJI- 447


447
La concurrence d’accès

• Le problème : espace de travail commun, pas de


"mémoire privée" pour chaque thread :
– inconvénient : accès simultané à une même ressource
Il faut garantir l’accès exclusif à un objet pendant l’exécution
d’une ou plusieurs instructions
• Pour se faire : le mot-clé synchronized permet de gérer les
concurrence d’accès :
– d’une méthode
– d’un objet
– ou d’une instruction (ou d’un bloc)

ENSAM 2020-2021- T.HAJJI- 448


448
La synchronisation

• Basée sur la technique de l’exclusion mutuelle :


– à chaque objet Java est associé un « verrou » géré par le thread
quand une méthode (ou un objet) synchronized est accédée.
– garantit l’accès exclusif à une ressource (la section critique)
pendant l’exécution d’une portion de code.
• Une section critique :
– une méthode : déclaration précédée de synchronized
– une instruction (ou un bloc) : précédée de synchronized
– un objet : le déclarer synchronized
• Attention à l’inter-blocage !!
(problème du dîner des philosophes)
ENSAM 2020-2021- T.HAJJI- 449
449
Utiliser synchronized

• Pour gérer la concurrence d’accès à une méthode :


– si un thread exécute cette méthode sur un objet, un autre thread ne peut pas l’exécuter
pour le même objet
– en revanche, il peut exécuter cette méthode pour un autre objet
public synchronized void maMethode() {...}
• Pour Contrôler l’accès à un objet :
public void maMethode() { ...
synchronized(objet) {
objet.methode();}}
– l’accès à l’objet passé en paramètre de synchronized(Object) est réservé à un unique
thread.

ENSAM 2020-2021- T.HAJJI- 450


450
Exemple de synchronisation
class Impression {
synchronized public void imprime(String t) {
for (int i=0; i<t.length(); i++) { System.out.print(t.charAt(i));
} } }

class TPrint extends Thread {


static Impression mImp = new Impression();
String txt;
public TPrint(String t) {txt = t;}

public void run() {


for (int j=0; j<3; j++) {mImp.imprime(txt);}}

static public void main(String args[]) {


TPrint a = new TPrint("bonjour ");
TPrint b = new TPrint("au revoir ");
a.start();
b.start();
}}
ENSAM 2020-2021- T.HAJJI- 451
451
Daemons

• Un thread peut être déclarer comme daemon :


– comme le "garbage collector", l’"afficheur d’images",
...
– en général de faible priorité, il "tourne" dans une boucle
infinie
– arrêt implicite dès que le programme se termine
• Les méthodes :
– setDaemon() : déclare un thread daemon
– isDaemon() : ce thread est-il un daemon ?
ENSAM 2020-2021- T.HAJJI- 452
452
Les « ThreadGroup »

Pour contrôler plusieurs threads


• Plusieurs processus (Thread) peuvent s’éxécuter en même temps, il
serait utile de pouvoir les manipuler comme une seule entité
– pour les suspendre
– pour les arrêter, ...
Java offre cette possibilité via l’utilisation des groupes de threads :
java.lang.ThreadGroup
• on groupe un ensemble nommé de threads
• ils sont contrôlés comme une seule unité

ENSAM 2020-2021- T.HAJJI- 453


453
Les groupes de threads
• Une arborescence :
– la classe ThreadGroup permet de constituer une arborescence
de Threads et de ThreadGroups
– elle donne des méthodes classiques de manipulation récursives
d’un ensemble de threads : suspend(), stop(),
resume(), ...
– et des méthodes spécifiques : setMaxPriority(), ...
• Fonctionnement :
– la JVM crée au minimum un groupe de threads nommé main
– par défaut, un thread appartient au même groupe que celui qui l’a
crée (son père)
– getThreadGroup() : pour connaître son groupe

ENSAM 2020-2021- T.HAJJI- 454


454
Création d’un groupe de threads

• Pour créer un groupe de processus :


ThreadGroup groupe = new ThreadGroup("Mon groupe");
Thread p1 = new Thread(groupe, "P1");
Thread p2 = new Thread(groupe, "P2");
Thread p3 = new Thread(groupe, "P3");

• On peut créer des sous-groupes de threads pour la


création d’arbres sophistiqués de processus
– des ThreadGroup contiennent des ThreadGroup
– des threads peuvent être au même niveau que des
ThreadGroup
ENSAM 2020-2021- T.HAJJI- 455
455
Création de groupe de threads (suite)

ThreadGroup groupe1 = new ThreadGroup("GP1");


Thread p1 = new Thread(groupe1, "P1");
Thread p2 = new Thread(groupe1, "P2");
Thread p3 = new Thread(groupe1, "P3");
ThreadGroup groupe11 = new ThreadGroup(groupe1, "GP11");
Thread p4 = new Thread(groupe11, "P4");
Thread p5 = new Thread(groupe11, "P5");

ENSAM 2020-2021- T.HAJJI- 456


456
Contrôler les ThreadGroup

• Le contrôle des ThreadGroup passe par l’utilisation


des méthodes standards qui sont partagées avec
Thread :
resume(), suspend(), stop(), ...
– Par exemple : appliquer la méthode stop() à un
ThreadGroup revient à invoquer pour chaque Thread du
groupe cette même méthode
– ce sont des méthodes de manipulation récursive

ENSAM 2020-2021- T.HAJJI- 457


457
Avantages / Inconvénients des threads

• Programmer facilement des applications où des


traitements se résolvent de façon concurrente
(applications réseaux, par exemple)
• Améliorer les performances en optimisant
l'utilisation des ressources
• Code plus difficile à comprendre, peu réutilisable
et difficile à débuguer

ENSAM 2020-2021- T.HAJJI- 458


458
JAVA Sérialisation

HAJJI TARIK
Docteur en Informatique

ENSAM 2020-2021- T.HAJJI- 459


Sérialisation
La sérialisation est un procédé introduit dans le JDK
version 1.1 qui permet de rendre un objet persistant.
Cet objet est mis sous une forme sous laquelle il pourra
être reconstitué à l'identique.
Ainsi il pourra être stocké sur un disque dur ou transmis
au travers d'un réseau pour le créer dans une autre JVM.
C'est le procédé qui est utilisé par RMI.
La sérialisation est aussi utilisée par les beans pour
sauvegarder leurs états.

ENSAM 2020-2021- T.HAJJI- 460


Sérialisation
Au travers de ce mécanisme, Java fournit une façon
facile, transparente et standard de réaliser cette opération :
ceci permet de facilement mettre en place un mécanisme
de persistance.
Il est de ce fait inutile de créer un format particulier
pour sauvegarder et relire un objet.
Le format utilisé est indépendant du système
d'exploitation. Ainsi, un objet sérialisé sur un système
peut être réutilisé par un autre système pour récréer
l'objet.

ENSAM 2020-2021- T.HAJJI- 461


Sérialisation

 L'ajout d'un attribut à l'objet est automatiquement pris


en compte lors de la sérialisation.
 Attention toutefois, la désérialisation de l'objet doit se
faire avec la classe qui a été utilisée pour la
sérialisation.
 La sérialisation peut s'appliquer facilement à tous les
objets.

ENSAM 2020-2021- T.HAJJI- 462


Les classes et les interfaces de la
sérialisation
La sérialisation utilise:
I. L'interface:
Serializable

II. Les classes:


ObjectOutputStream
ObjectInputStream

ENSAM 2020-2021- T.HAJJI- 463


L'interface Serializable

Cette interface ne définit aucune méthode mais permet


simplement de marquer une classe comme pouvant être
sérialisée.
Tout objet qui doit être sérialisé doit implémenter cette
interface ou une de ses classes mères doit l'implémenter.
Si l'on tente de sérialiser un objet qui n'implémente pas
l'interface Serializable, une exception
NotSerializableException est levée.

ENSAM 2020-2021- T.HAJJI- 464


public class Personne implements java.io.Serializable {
private String nom = "";
private String prenom = "";
private int taille = 0;
public Personne(String nom, String prenom, int taille) {
this.nom = nom;
this.taille = taille;
this.prenom = prenom;
}
public String getNom() { return nom;}
public void setNom(String nom) { this.nom = nom;}
public int getTaille() { return taille;}
public void setTaille(int taille) { this.taille = taille;}
public String getPrenom() { return prenom;}
public void setPrenom(String prenom) {this.prenom = prenom;}
}

ENSAM 2020-2021- T.HAJJI- 465


La classe ObjectOuputStream
Cette classe permet de sérialiser un objet.
import java.io.*;
public class SerializerPersonne {
public static void main(String argv[]) {
Personne personne = new Personne("Dupond","Jean",175);
try {
FileOutputStream fichier = new FileOutputStream("personne.ser");
ObjectOutputStream oos = new ObjectOutputStream(fichier);
oos.writeObject(personne);
oos.flush();
oos.close();
}catch (java.io.IOException e) {
e.printStackTrace();
}
}
}

ENSAM 2020-2021- T.HAJJI- 466


On définit un fichier avec la classe FileOutputStream.
On instancie un objet de classe ObjectOutputStream en
lui fournissant en paramètre le fichier : ainsi, le résultat de
la sérialisation sera envoyé dans le fichier.
On appelle la méthode writeObject() en lui passant en
paramètre l'objet à sérialiser.
On appelle la méthode flush() pour vider le tampon dans
le fichier et la méthode close() pour terminer l'opération.
Lors de ces opérations une exception de type
IOException peut être levée si un problème intervient avec
le fichier.

ENSAM 2020-2021- T.HAJJI- 467


Après l'exécution de cet exemple, un fichier nommé
« personne.ser » est créé.
On peut visualiser son contenu mais surtout pas le modifier car
sinon il serait corrompu.
En effet, les données contenues dans ce fichier ne sont pas toutes
au format caractères.
La classe ObjectOutputStream contient aussi plusieurs
méthodes qui permettent de sérialiser des types élémentaires et non
des objets : writeInt(), writeDouble(), writeFloat(), ...
Il est possible dans un même flux d'écrire plusieurs objets les uns
à la suite des autres.
Ainsi plusieurs objets peuvent être sauvegardés.
Dans ce cas, il faut faire attention de relire les objets dans leur
ordre d'écriture.
ENSAM 2020-2021- T.HAJJI- 468
La classe ObjectInputStream
Cette classe permet de désérialiser un objet.
import java.io.*;
public class DeSerializerPersonne {
public static void main(String argv[]) {
try {
FileInputStream fichier = new FileInputStream("personne.ser");
ObjectInputStream ois = new ObjectInputStream(fichier);
Personne personne = (Personne) ois.readObject();
System.out.println("Personne : ");
System.out.println("nom : "+personne.getNom());
System.out.println("prenom : "+personne.getPrenom());
System.out.println("taille : "+personne.getTaille());
}catch (java.io.IOException e) {
e.printStackTrace();
C:\dej>java DeSerializerPersonne
}catch (ClassNotFoundException e) {
Personne :
e.printStackTrace();
} nom : Dupond
} prenom : Jean
} taille : 175

ENSAM 2020-2021- T.HAJJI- 469


On crée un objet de la classe FileInputStream qui
représente le fichier contenant l'objet sérialisé puis un objet
de type ObjectInputStream en lui passant le fichier en
paramètre.
Un appel à la méthode readObject() retourne l'objet avec
un type Object.
 Un cast est nécessaire pour obtenir le type de l'objet.
La méthode close() permet de terminer l'opération.
Si la classe a changé entre le moment où elle a été
sérialisée et le moment où elle est désérialisée, une
exception est levée.

ENSAM 2020-2021- T.HAJJI- 470


C:\temp>java DeSerializerPersonne
java.io.InvalidClassException: Personne; Local class not compatible: stream
class
desc serialVersionUID=-2739669178469387642 local class
serialVersionUID=39870587
36962107851
atjava.io.ObjectStreamClass.validateLocalClass(ObjectStreamClass.java:4
38)
at java.io.ObjectStreamClass.setClass(ObjectStreamClass.java:482)
at java.io.ObjectInputStream.inputClassDescriptor(ObjectInputStream.java
:785)

ENSAM 2020-2021- T.HAJJI- 471


Une exception de type StreamCorruptedException peut
être levée si le fichier a été corrompu par exemple en le
modifiant avec un éditeur.
Exemple : les 2 premiers octets du fichier personne.ser
ont été modifiés avec un éditeur.
C:\temp>java DeSerializerPersonne
java.io.StreamCorruptedException: InputStream does not contain a serialized object at
java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:731)
At java.io.ObjectInpDutStream.<init>(ObjectInputStream.java:165) at
eSerializerPersonne.main(DeSerializerPersonne.java:8)

ENSAM 2020-2021- T.HAJJI- 472


Une exception de type ClassNotFoundException peut
être levée si l'objet est transtypé vers une classe qui n'existe
plus ou pas au moment de l'exécution.
Exemple ( code Java 1.1 ) :

C:\temp>rename Personne.class Personne2.class


C:\temp>java DeSerializerPersonne
java.lang.ClassNotFoundException: Personne
at java.io.ObjectInputStream.inputObject(ObjectInputStream.java:981)
at java.io.ObjectInputStream.readObject(ObjectInputStream

ENSAM 2020-2021- T.HAJJI- 473


La classe ObjectInputStream possède de la
même façon que la classe
ObjectOutputStream des méthodes pour lire
des données de type primitives :
readInt(),
readDouble(),
readFloat(), ...
Lors de la désérialisation, le constructeur de
l'objet n'est jamais utilisé.
ENSAM 2020-2021- T.HAJJI- 474
Le mot clé transient
Le contenu des attributs est visible dans le flux dans lequel est sérialisé
l'objet. Il est ainsi possible pour toute personne ayant accès au flux de voir le
contenu de chaque attribut même si ceux-ci sont private, ce qui peut poser des
problèmes de sécurité surtout si les données sont sensibles.
Java introduit le mot clé transient qui précise que l'attribut qu'il qualifie ne
doit pas être inclus dans un processus de sérialisation et donc de
désérialisation.
Exemple ( code Java 1.1 ) :
...
private transient String codeSecret;
Lors de la désérialisation, les champs transient sont initialisés avec la valeur
null. L'objet recréé doit donc gérer cet état pour éviter d'avoir des exceptions
de type NullPointerException.

ENSAM 2020-2021- T.HAJJI- 475


La sérialisation personnalisée

Il est possible de personnaliser la sérialisation d'un objet.


Dans ce cas, la classe doit implémenter l'interface
Externalizable qui hérite de l'interface Serializable.

ENSAM 2020-2021- T.HAJJI- 476


L'interface Externalizable

Cette interface définit deux méthode :


readExternal()
writeExternal().
Par défaut, la sérialisation d'un objet qui implémente cette
interface ne prend en compte aucun attribut de l'objet.
Remarque : le mot clé transient est donc inutile avec une classe
qui implémente l'interface Externalisable

ENSAM 2020-2021- T.HAJJI- 477


TP-1

On vous demande dans ce TP de implémenter


un programme JAVA composé par une classe
Rectangle, qui est composée par 4 Points.
On vous demande d’exécuter ce programme
4 fois, telle que dans chaque exécution on
rajoute la définition d’un point du rectangle.

ENSAM 2020-2021- T.HAJJI- 478

Vous aimerez peut-être aussi