Vous êtes sur la page 1sur 106

Table des matières

Page
Table des matières . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1 Présentation Générale de Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.1 Principe de fonctionnement . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.1.1 Le compilateur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.1.2 La machine virtuelle . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.1.3 L’interpréteur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.2 Caractéristique objet de Java . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.2.1 La notion d’objet . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.2.2 La notion de classe . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.3 Création d’une application Java . . . . . . . . . . . . . . . . . . . . . . . . 10
1.3.1 Définition et création d’une application . . . . . . . . . . . . . . . . 10
1.3.2 Les paramètres de la méthode main . . . . . . . . . . . . . . . . . . 11
1.3.3 Organisation d’une application Java . . . . . . . . . . . . . . . . . . 13
1.4 Exercices d’application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2 Éléments de Base de Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.1 Les types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.1.1 Gestion de la mémoire . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.1.2 Les types primitifs . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.1.3 Les types références . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.1.4 Le transtypage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.2 Les instructions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
2.2.1 Les structures conditionnelles . . . . . . . . . . . . . . . . . . . . . 19
2.2.2 Les structures itératives (ou boucles) . . . . . . . . . . . . . . . . . 21
2.2.3 Les instructions de saut . . . . . . . . . . . . . . . . . . . . . . . . 23
2.3 Exercices d’application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
3 Programmation Orientée Objet . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
3.1 L’approche objet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
3.2 Les concepts de base de l’approche objet . . . . . . . . . . . . . . . . . . . 28
3.2.1 Objet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
3.2.2 Communication entre les objets . . . . . . . . . . . . . . . . . . . . 29
3.2.3 Encapsulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
3.2.4 Classe et instanciation . . . . . . . . . . . . . . . . . . . . . . . . . 30
3.2.5 Constructeur et Destructeur . . . . . . . . . . . . . . . . . . . . . . 31
3.2.6 Héritage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
3.2.7 Polymorphisme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
3.3 Implémentation en Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
3.3.1 Les classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
3.3.2 Instanciation des objets . . . . . . . . . . . . . . . . . . . . . . . . 39
3.3.3 Appel des méthodes . . . . . . . . . . . . . . . . . . . . . . . . . . 40
1
TABLE DES MATIÈRES 2
3.3.4 La référence sur l’objet courant . . . . . . . . . . . . . . . . . . . . 41
3.3.5 Les membres statiques . . . . . . . . . . . . . . . . . . . . . . . . . 42
3.3.6 Les tableaux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
3.3.7 Types des tableaux . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
3.4 Exercices d’application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
4 Héritage et Polymorphisme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
4.1 Héritage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
4.1.1 Définition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
4.1.2 Syntaxe de l’héritage . . . . . . . . . . . . . . . . . . . . . . . . . . 53
4.1.3 Enchaı̂nement des constructeurs . . . . . . . . . . . . . . . . . . . . 54
4.1.4 Propriétés des constructeurs . . . . . . . . . . . . . . . . . . . . . . 54
4.1.5 Redéfinition des méthodes . . . . . . . . . . . . . . . . . . . . . . . 55
4.1.6 Les modes de protection . . . . . . . . . . . . . . . . . . . . . . . . 56
4.1.7 Portée des méthodes redéfinies . . . . . . . . . . . . . . . . . . . . . 57
4.1.8 Interdire la redéfinition et bloquer l’héritage . . . . . . . . . . . . . 58
4.2 Polymorphisme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
4.2.1 Définition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
4.2.2 Le polymorphisme des méthodes . . . . . . . . . . . . . . . . . . . . 59
4.2.3 Le polymorphisme des objets . . . . . . . . . . . . . . . . . . . . . 60
4.2.4 L’opérateur instanceof . . . . . . . . . . . . . . . . . . . . . . . . . 62
4.2.5 Tableaux polymorphes . . . . . . . . . . . . . . . . . . . . . . . . . 63
4.3 Exercices d’application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
5 Classes Abstraites et Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
5.1 Les classes abstraites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
5.2 Les interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
5.2.1 Définition et déclaration d’une interface . . . . . . . . . . . . . . . . 70
5.2.2 Implémentation d’une interface . . . . . . . . . . . . . . . . . . . . 70
5.2.3 Implémentation de plusieurs interfaces . . . . . . . . . . . . . . . . 71
5.2.4 Dérivation d’une interface . . . . . . . . . . . . . . . . . . . . . . . 74
6 Gestion des Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
6.1 Définition de l’exception . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
6.2 La hiérarchie des classes des erreurs et des exceptions . . . . . . . . . . . . 79
6.3 Lever une exception . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
6.4 Traitement d’une exception . . . . . . . . . . . . . . . . . . . . . . . . . . 80
6.4.1 Capturer une exception . . . . . . . . . . . . . . . . . . . . . . . . . 80
6.4.2 Propagation d’une exception . . . . . . . . . . . . . . . . . . . . . . 83
6.5 Les sources d’exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
6.6 Exercices d’application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
7 Utilisation de bases de données avec JDBC . . . . . . . . . . . . . . . . . . . . . 88
7.1 Classes de JDBC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
7.2 Connexion à la base de données . . . . . . . . . . . . . . . . . . . . . . . . 89
7.2.1 Prérequis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
7.2.2 Chargement du driver . . . . . . . . . . . . . . . . . . . . . . . . . 89
7.2.3 Identification de l’URL . . . . . . . . . . . . . . . . . . . . . . . . . 90
TABLE DES MATIÈRES 3

7.2.4 Établissement de la connexion . . . . . . . . . . . . . . . . . . . . . 90


7.3 Accès à la base de données . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
7.3.1 Interrogation de la base de données . . . . . . . . . . . . . . . . . . 91
7.3.2 Exploitation du résultat . . . . . . . . . . . . . . . . . . . . . . . . 92
7.4 Libération des ressources . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
7.5 Exercices d’application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
8 Les collections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
8.1 Hiérarchie de Collection Framework . . . . . . . . . . . . . . . . . . . . . . 95
8.1.1 Interface Iterable . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
8.1.2 Interface Collection . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
8.2 Interface List . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
8.2.1 La classe ArrayList . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
8.3 Interface Set . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
8.3.1 HashSet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
9 Paquetages et quelques classes en Java . . . . . . . . . . . . . . . . . . . . . . . 100
9.1 Les paquetages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
9.1.1 Attribution d’une classe à un paquetage . . . . . . . . . . . . . . . 100
9.1.2 Les paquetages standard . . . . . . . . . . . . . . . . . . . . . . . . 102
9.2 Quelques classes d’usage fréquent . . . . . . . . . . . . . . . . . . . . . . . 102
9.2.1 La classe Scanner . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
9.2.2 La classe Math . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
9.2.3 La classe Date . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
Chapitre 1

Présentation Générale de Java

Java est un langage de programmation purement orienté objet. La première version de


Java a été créée en 1995 par la société Sun Microsystems et la version actuelle Java SE
17 (14 septembre 2021). La société a été rachetée par Oracle en 2009.
Le langage Java est compilé et interprété et sa syntaxe est proche des langages C et
C++.
Ce langage a été créé pour être fonctionnel au sien d’une architecture réseau de machines
de systèmes d’exploitation hétérogènes (portabilité).
Java a été développé pour surmonter les limites de la programmation fonctionnelle ou
procédurale, comme :
− Les points critiques du C++ : les pointeurs, la surcharge des opérateurs et l’héritage
multiple ;
− dissociation entre les données et les traitements ;
− difficulté de maintenance et réutilisation des programmes ;
− difficulté d’évolution et extensibilité des programmes.

Plusieurs environnements Java sont disponibles :


− Java SE (Standard Edition) ;
− Java ME (Mobile Edition) ;
− Java EE (Enterprise Edition).

Des environnements de développements gratuits sont disponibles, par exemple :


− NetBeans ;
− Eclipce ;
− En ligne : https ://replit.com/

1.1 Principe de fonctionnement


Java est conçu pour être un langage de programmation indépendant de la plate-forme
matérielle et logicielle sur laquelle il s’exécute. Pour atteindre cet objectif (la portabilité),
les concepteurs du langage ont réalisé trois outils qui constituent la base de fonctionnement
des programmes Java, à savoir :

− Java Virtual Machine (JVM) : la machine virtuelle “couche logicielle” qui isole les
programmes écrits en Java des contraintes des systèmes d’exploitation.

− Java Runtime Environment (JRE) : désigne le conteneur de l’environnement d’exécution


4
CHAPITRE 1. PRÉSENTATION GÉNÉRALE DE JAVA 5

de programmes Java sur toutes les plates-formes. Le JRE désigne la JVM et l’ensemble des
outils nécessaires (bibliothèques standard) pour exécuter des programmes en Java. Le JRE
interprète le byte code en un langage propre au système d’exploitation. Il existe donc
plusieurs JRE, chacun associé à un système d’exploitation.
− Java Developpment Kit (JDK) : outils de développement permettant essentiellement
de compiler du code Java pour produire un code portable (byte code) pour n’importe
quel système d’exploitation. Il inclut un compilateur, un interpréteur et un environnement
de développement comprenant les outils et utilitaires favorisant la programmation.

Figure 1.1: Principe de fonctionnement d’un programme Java

—- Reportez-vous à cette vidéo pour comprendre


la différence entre JVM, JRE et JDK.

Dans ce qui suit, nous présenterons une idée générale pour expliquer le principe de
fonctionnement de ces outils.

1.1.1 Le compilateur
Le programme javac est le principal compilateur de Java faisant partie du JDK. Il
est écrit entièrement en Java et disponible sur n’importe quelle plateforme qui permet
l’exécution de programmes Java.

Le compilateur javac transforme le code source Java (.java) en un code intermédiaire


portable appelé bytecode (.class).

La compilation d’un programme Java doit se faire avec l’exécution du programme javac.
CHAPITRE 1. PRÉSENTATION GÉNÉRALE DE JAVA 6

Syntaxe :
javac nomFichier.java

,→ Cette commande produit un fichier nomFichier.class (byte code) et l’enregistre


dans le même répertoire que celui du code source.

Nous pourrons effectuer une redirection du fichier résultant vers un autre répertoire en
utilisant l’option “d”.

Syntaxe :
javac -d cheminDestination nomFichier.java

Nous pourrons compiler plusieurs fichiers “.java” en même temps et regrouper tous les
fichiers “.class” dans un même répertoire.

Syntaxe :
javac -d cheminDestination nomFichier1.java nomFichier2.java ...

1.1.2 La machine virtuelle


C’est une couche logicielle intermédiaire entre les systèmes d’exploitation et les pro-
grammes écrits en Java.

Elle isole les programmes Java des contraintes de l’environnement local, assurant ainsi
leur portabilité.

Pour qu’un système puisse faire tourner des programmes Java, il faut que la JVM soit
portée sur le système en question.

Nous pouvons développer un programme Java sous Linux et l’exécuter dans des envi-
ronnements divers. Pour cela, les programmes Java compilés n’utilisent pas directement le
processeur de la machine, ils se servent d’une machine virtuelle Java, c’est un programme
qui se charge d’interpréter de code compilé et l’adapter à la machine sur laquelle il tourne.

1.1.3 L’interpréteur
Un interpréteur Java est un logiciel qui implémente la machine virtuelle et qui exécute
les programmes Java.

L’interpréteur est activé explicitement en utilisant la commande java suivie du nom du


fichier bytecode à exécuter.
CHAPITRE 1. PRÉSENTATION GÉNÉRALE DE JAVA 7

Syntaxe :
java nomFichier

L’interpréteur gère toutes les activités du système d’exécution Java, il charge des fichiers
“.class” et interprète le bytecode compilé. En d’autres termes, il lit chaque instruction
du fichier “.class” et la traduit dans le langage du processeur et lance son exécution, puis
il prend en charge l’instruction suivante.

Les systèmes qui veulent exécuter un programme Java doivent fournir un interpréteur.
À l’heure actuelle, les JVM sont fournis avec les systèmes d’exploitation Linux, Windows,
Macintosh, etc. C’est le JRE qui va traduire donc le bytecode en un langage propre au
système d’exploitation utilisé.

1.2 Caractéristique objet de Java


Java est un langage purement orienté objet. En effet, un programme Java est basé
complètement sur les objets. Excepté les types fondamentaux de données, tout est objet.

1.2.1 La notion d’objet


Les objets sont les acteurs principaux d’un programme écrit en Java. Leur rôle principal
consiste à sauvegarder des informations et à mettre à disposition une collection d’opérations
qui permettent d’accéder à ces informations et de les modifier.

Les objets regroupent les principales caractéristiques des éléments du monde réel. Un
objet est caractérisé par :

− ses attributs : il s’agit de données dont les valeurs caractérisent l’état l’objet.

− ses méthodes : caractérisent son comportement, c’est-à-dire l’ensemble des opérations


que l’objet peut réaliser.

− son identité : l’objet possède une identité qui permet de le distinguer des autres
objets. Cette identité est donnée par le système.
CHAPITRE 1. PRÉSENTATION GÉNÉRALE DE JAVA 8

Exemple : Soient deux objets objet1 et objet2 représentant deux personnes différentes.

Figure 1.2: Exemple d’objets

N.B. : Par convention, un nom d’objet commence par une lettre minuscule. S’il est
composé de plusieurs mots, chaque mot (à part le premier) commence par majuscule et le
reste en minuscule.

1.2.2 La notion de classe


Les objets Java sont similaires aux objets du monde réel. Chaque objet est une instance
d’une classe. C’est la classe qui spécifie le type des informations qui seront contenues par
les objets, et qui spécifient également les opérations qui peuvent agir sur ces informations.

Figure 1.3: Classe vs objet

La classe est donc la structure d’un objet c-à-d la déclaration de l’ensemble des parties
qui composeront un objet. Une classe est alors composée de deux parties :

− Les attributs : il s’agit de données caractérisant les objets.


− Les méthodes : il s’agit des opérations applicables sur les attributs des objets.

. La création d’un objet par une classe est appelée instanciation.

Soit une classe appelée ExempleClasse instanciée en deux objets objet1 et objet2.
Cette instanciation peut être schématisée comme suit :
CHAPITRE 1. PRÉSENTATION GÉNÉRALE DE JAVA 9

Figure 1.4: Schéma d’instanciation d’une classe en deux objets

N.B. : par convention,


• un nom de classe commence par une lettre majuscule. S’il est composé de plusieurs mots,
chaque mot commence aussi par majuscule et le reste en minuscule. Il est préférable que
le nom d’une classe contienne des mots complets que des abréviations.
• les noms des attributs d’une classe commencent par une lettre minuscule. S’ils sont com-
posés de plusieurs mots, chaque mot (sauf le premier) commence par majuscule et le reste
en minuscule.
• le nom d’une méthode soit un verbe écrit en minuscule. S’il est composé de plusieurs
mots, ces derniers commenceront par une lettre majuscule sauf le premier.

Exemple : soit une classe Personne caractérisée par :


− les attributs : nom, prénom et ville.
− la méthode : afficher() pour afficher toutes les informations d’une personne.

Soient deux objets personne1 et personne2 créés par la classe Personne. Ils peuvent
avoir les valeurs suivantes pour leurs attributs :

Figure 1.5: Exemple de classe instanciée en deux objets


CHAPITRE 1. PRÉSENTATION GÉNÉRALE DE JAVA 10

1.3 Création d’une application Java


1.3.1 Définition et création d’une application
Une application est un programme écrit dans le langage de programmation Java et
exécuté par la machine virtuelle de la plateforme Java.

La classe de lancement d’une application n’a besoin que d’un seul élément : une méthode
principale main. En Java, la méthode main doit obligatoirement exister à l’intérieur d’une
classe de lancement.

Syntaxe :

public class NomClasse {


public static void main (String args []) {
...
}
}

avec :
− pour la classe, sa caractéristique public indique qu’elle peut être accessible à partir
d’autres classes dans des paquetages différents (voir chapitre 3).

− pour la méthode main, la caractéristique :


• public : indique que la méthode main est accessible à d’autres classes.

• static : signifie qu’il s’agit d’une méthode de classe (voir chapitre 3).

• void : indique que cette méthode ne retourne pas de résultats.

• main (String args []) : prend un paramètre, qui est un tableau de chaı̂nes de ca-
ractères “String”. Il s’agit des paramètres de la ligne de commande qui exécute la méthode
main (qui sera traitée dans la section suivante). Le corps de cette méthode contient le code
nécessaire à l’exécution de l’application : l’initialisation des variables ou la création d’ins-
tances des classes qui ont été déclarées (s’il y en a) et les instructions de manipulation de
ces variables ou instances.

Exemple : pour la classe TestBonjour, nous pourrons afficher le message “Bonjour”.


Cette classe contient la méthode main suivante :
CHAPITRE 1. PRÉSENTATION GÉNÉRALE DE JAVA 11

public class TestBonjour {


public static void main (String args []) {
System.out.println(‘‘Bonjour’’);
}
}

,→ System est une classe qui se réfère au système dans lequel le programme s’exécute ;
out est l’objet de sortie par défaut (écran) ; la fonction println imprime son paramètre
String sur le périphérique de sortie suivi d’un saut de ligne.

1.3.2 Les paramètres de la méthode main


Les paramètres en ligne de commande servent à communiquer à une application toutes
les informations utiles à son fonctionnement.

Passage des paramètres à une application Java


Le mode de passage des paramètres dépend de la plateforme d’exécution de Java. Sur
les systèmes Linux et Windows, il est possible de passer des paramètres par la ligne de
commandes. Sur Macintosh, le programme Java Runner fournit une fenêtre spéciale pour
saisir ces paramètres.

Exemple : Si nous voulons exécuter le même programme de la classe TestBonjour avec


les paramètres args[0]=”SMI” et args[1]=”S5”, le code source sera alors comme suit :

public class TestBonjour {


public static void main (String args []) {
System.out.println(‘‘Bonjour’’);
System.out.println(args[0]);
System.out.print(args[1]);
}
}

N.B. : En Java args[0] est le premier paramètre de la ligne de commande.

La commande d’exécution de ce programme pourra être la suivante :

java TestBonjour SMI S5

Le résultat d’exécution de ce programme est le suivant :


CHAPITRE 1. PRÉSENTATION GÉNÉRALE DE JAVA 12

Bonjour
SMI
S5

Traitement des paramètres dans une application Java


Java range les paramètres dans le tableau args (nous pouvons choisir librement le nom
de ce tableau) de chaı̂nes de caractères passées à la méthode main de l’application Java.

Au sein de la main, nous pouvons traiter les paramètres transmis au programme au


moyen de manipulation du tableau, et faire de ces paramètres le traitement désiré.

Sur la ligne de commande d’exécution, un paramètre est toujours pris en considération


sous forme d’un String. Si nous voulons qu’un paramètre soit d’une valeur entière, il faut
faire une conversion de la valeur du paramètre du type String en un type int. Pour cela,
nous pouvons utiliser la fonction suivante :

Integer.parseInt(chaı̂ne)

,→ Cette commande retourne la valeur entière, écrite sous forme de chaı̂ne de caractères,
de la variable cha^
ıne.

Pour convertir la valeur un paramètre du type String en un type float, nous pouvons
utiliser la fonction suivante :

Float.parseFloat(chaı̂ne)

Exemple : Le programme qui permet d’afficher le paramètre sous forme d’un entier est
le suivant :

public class TestBonjour {


public static void main (String args []) {
int val=Integer.parseInt(args[0]);
System.out.println(‘‘La valeur du paramètre est:’’+val);
}
}
CHAPITRE 1. PRÉSENTATION GÉNÉRALE DE JAVA 13

1.3.3 Organisation d’une application Java


Une application Java peut être organisée en un ou plusieurs fichiers. Un fichier peut
contenir une ou plusieurs classes. Le nom d’un fichier aura l’extension “.java”.

Si le fichier contient une seule classe, il est important que le nom de ce fichier corres-
ponde au nom de la classe. Si le fichier contient plusieurs classes, il doit y avoir au moins
une classe qui porte le même nom de ce fichier.

Une application Java doit contenir une seule méthode main. Généralement, la classe qui
contient la méthode main ne contient pas d’autres méthodes.
CHAPITRE 1. PRÉSENTATION GÉNÉRALE DE JAVA 14

1.4 Exercices d’application

Exercice 1.1
1. Créez votre propre répertoire de travail (par exemple : C :\SMI5\B2\PC\TP1).
2. Écrivez le programme Bonjour.java suivant en utilisant un éditeur de texte :

public class Bonjour {


public static void main (String args [ ]) {
System.out.println("Bonjour SMI S5");
}
}

3. Compilez le programme avec la commande : javac Bonjour.java


4. Quel est le fichier généré ?
5. Lancez l’exécution du programme avec la commande : java Bonjour
6. Quel est le résultat d’exécution du programme ?
Chapitre 2

Éléments de Base de Java

2.1 Les types


Le système de typage d’un langage de programmation décrit la manière dont ses données
(variables et constantes) sont codées. En Java, les types de données sont répertoriés en deux
catégories :

− Les types primitifs : représentent des valeurs simples qui ont des fonctionnalités
prédéfinies par le langage. Exemple : byte, short, int, long, float, double, et char.
− Les types références (ou types de classes) : représentent des valeurs complexes
incluent des objets et des tableaux dont les fonctionnalités doivent être définies.
Exemple : String.

2.1.1 Gestion de la mémoire


• Toutes les données des variables du type primitif sont stockées sur la stack.
• Pour les types références, la stack contient un pointeur vers l’objet sur le heap.
• Lors de la définition d’une variable de type référence égale à une autre variable de
type référence, une copie du seul pointeur est effectuée.

Figure 2.1: Stack vs Heap

15
CHAPITRE 2. ÉLÉMENTS DE BASE DE JAVA 16

2.1.2 Les types primitifs


Les valeurs de type numérique, de type caractère et de type booléen peuvent être uti-
lisées comme des types simples (pour simplifier leur utilisation) ou comme des objets.
Les types primitifs sont de l’ordre de huit (comme indiqué dans le tableau suivant) :

Type Taille mémoire Valeur par défaut


boolean 1 bit fasle
byte 1 octet (byte) 0
char 2 octets null ou ‘\u0000’
short 2 octets (short) 0
int 4 octets 0
long 8 octets 0l ou 0L
float 4 octets 0.0f ou 0.0F
double 8 octets 0.0d ou 0.0D

− Le type boolean ne peut avoir des valeurs que true ou false.


− Les entiers peuvent avoir pour type int. Ils peuvent être également suffixés par la
lettre l (ou L), indiquant qu’il s’agit d’un entier long.
− Les nombres double peuvent être suffixé par la lettre d (ou D).
− Si un nombre réel est suffixé par la lettre f (ou F), il sera considéré comme un float.

Exemples :
boolean b = true;
char c = ‘m’;
int val = 19;
long l = 13L;
double d = 3.7;
float f = 7.1F;

2.1.3 Les types références


Un type référence est un type non primitif. Les types références sont utilisés pour
désigner des objets c’est à dire des instances de classes ou des tableaux (chapitre 3).
Toute variable dont le type associé n’est pas un type primitif est qualifiée de type
référence. Le rôle d’une telle variable sera de référencer une zone mémoire contenant un
objet du type correspondant. La déclaration des variables de référence n’entraı̂ne pas une
allocation de la mémoire susceptible de contenir une grandeur du type référencé. Seul est
alloué l’espace nécessaire à la mémorisation d’une adresse (ou référence). L’espace mémoire
nécessaire devra être alloué explicitement au travers de l’opérateur spécifique new qui réalise
la construction d’un objet crée. Les variables de type référence sont initialisées par défaut
à la valeur null (chapitre 3).
CHAPITRE 2. ÉLÉMENTS DE BASE DE JAVA 17

Exemple :

String s;

Cette instruction permet de créer une référence appelée s contenant la valeur null.

2.1.4 Le transtypage
Le transtypage permet de convertir une donnée d’un type primitif (sauf le boolean) ou
d’un type référence en un nouveau type.
Un transtypage peut être fait :
− entre deux types primitifs.
− ou entre deux types références.

a. Transtypage d’un type primitif


Le transtypage d’un type primitif permet de convertir un objet d’un type primitif à un
autre type primitif compatible. Ce type de transtypage peut être implicite ou explicite.
• Transtypage implicite

Le compilateur Java prend toujours en charge, de manière automatique, la conversion d’un


type primitif à un autre, selon la règle à respecter suivante :

typeMoinsLarge → typePlusLarge

Les différents types primitifs peuvent être classés selon la règle de conversion comme
suit :

byte → short → int → long → float → double


char → int

En effet, une variable de type float, par exemple, pourra être convertie en un double,
mais l’inverse n’est pas évident.
CHAPITRE 2. ÉLÉMENTS DE BASE DE JAVA 18

Exemple :

double d=5.0;
float f=3.0F;
int i;
// le compilateur autorise le transtypage
// implicite suivant:
d=f;
// il s’agit de convertir f en un double
i=d;
/* erreur : le système ne peut pas convertir implicitement un
double en un entier */

Lorsqu’un transtypage implicite illégal est tenté, alors une erreur est déclenchée (excep-
tion lancée : voir chapitre 6) indiquant une incompatibilité de type.
• Transtypage explicite

Le transtypage explicite permet de spécifier, directement dans le code, le type que l’on
souhaite donner à une variable.

Syntaxe :

(type) expression ;

Exemple :

float f = 7.3F;
int i;
i = (int) f;

Pour les types primitifs, il est possible d’être confronté à une perte d’informations
lorsque le type de transtypage est moins large que celui de l’origine.

b. Transtypage d’un type référence


Ce transtypage permet de convertir un objet d’un type non primitif à un autre type non
primitif. Il ne manipule que des références : il ne change pas la forme de l’objet. En effet,
convertir un objet, ne change pas un objet pointé par une référence, mais on ne change que
sa représentation vis-à-vis du compilateur.
Le principe de transtypage de référence permet d’adapter la référence d’un objet à une
variable objet d’un type différent. Ce transtypage fait appel à la notion du polymorphisme :
un objet peut avoir plusieurs types (chapitre 4).
CHAPITRE 2. ÉLÉMENTS DE BASE DE JAVA 19

2.2 Les instructions


2.2.1 Les structures conditionnelles
Une condition est une expression booléenne. Une structure conditionnelle peut être à
choix simple ou multiple ; elle teste sur la valeur d’une condition (vraie ou fausse).

• Les structures de choix simple

Syntaxe :
if(condition){
// instructions si la condition est vraie;
}
else {
// instructions si la condition est fausse;
}

− La condition doit être entourée de parenthèses.


− Chaque instruction est terminée par un point-virgule.
− Les accolades (ne sont pas suivies par un point-virgule) ne sont nécessaires que s’il y
a plus d’une instruction.
− Le bloc else peut être absent.

Exemple : le programme permet de chercher le maximum entre


deux valeurs entières.

public class Maximum {


public static void main (String args [ ]) {
int a = 7;
int b = 19;
if (a > b)
System.out.println("a = "+a+" est plus grande
que b = "+b);
else
System.out.println("b = "+b+" est plus grande
que a = "+a);
}
}

Nous pouvons avoir des structures de choix simples imbriquées.


CHAPITRE 2. ÉLÉMENTS DE BASE DE JAVA 20

Syntaxe :
if (condition1)
[ if (condition2) {
// instructions si condition1=vraie et condition2=vraie
}
[ else { //condition2
// instructions si condition1=vraie et condition2=fausse
}
]
]
[ else { //condition1
// instructions si condition1=fausse
}
]

• Les structures de choix multiples (ou sélective)


Si dans le cas d’un schéma conditionnel imbriqué, la condition porte sur la même variable
(ou expression), nous pouvons utiliser la sélective. Il s’agit de sélectionner un traitement,
selon la valeur de l’expression après évaluation. Cette expression est appelée sélecteur.

Syntaxe :
switch (sélecteur) {
case valeur1 :
// liste des instructions si sélecteur = valeur1;
[ break; ]
case valeur2 :
// liste des instructions si sélecteur = valeur2;
[ break; ]
...
[default :
// liste des instructions si aucune valeur n’est
choisie ]
}

− La valeur du sélecteur, ne peut être qu’un byte, short, int ou un char.


− Le sélecteur est entouré de parenthèses.
− La clause default peut être absente.
− Les valeurs, valeuri sont des valeurs possible du sélecteur. Si le sélecteur a pour
valeur valeuri , les instructions préfixées par la clause case valeuri sont exécutées.
− L’instruction break fait sortir de la structure de case. Si elle est absente à la fin du
bloc d’instructions de la valeur (valeuri ), l’exécution se poursuit alors avec les instru-
ctions de la valeur valeuri+1 .
CHAPITRE 2. ÉLÉMENTS DE BASE DE JAVA 21

Exemple : un programme qui affiche le nom du jour selon la valeur d’une


variable entière.

public class Jour {


public static void main (String args [ ]) {
int jour = 4;
switch (jour) {
case 1 : System.out.println("Dimanche"); break;
case 2 : System.out.println("Lundi"); break;
case 3 : System.out.println("Mardi"); break;
case 4 : System.out.println("Mercredi"); break;
case 5 : System.out.println("Jeudi"); break;
case 6 : System.out.println("Vendredi"); break;
case 7 : System.out.println("Samedi"); break;
default : System.out.println("numéro du jour erroné");
}
}
}

2.2.2 Les structures itératives (ou boucles)


Les instructions itératives se basent sur des conditions sous forme d’expressions booléennes.
Un ensemble d’instructions sera répété selon le résultat d’évaluation de la condition.

• Structure while

Syntaxe :
while(conditions){
//ensemble d’instructions;
}

Les instructions sont répétées tant que les conditions sont vérifiées. La boucle peut ne
jamais être exécutée si la condition est fausse dès la première itération.

N.B. : − Les conditions sont entourées de parenthèses.


——— − Chaque instruction est terminée par un point-virgule.
——— − L’accolade n’est nécessaire que s’il y a plus d’une instruction.
——— − L’accolade n’est pas suivie de point-virgule.
CHAPITRE 2. ÉLÉMENTS DE BASE DE JAVA 22

• Structure do while

Syntaxe :
do {
//ensemble d’instructions
}while(conditions);

Les instructions sont exécutées jusqu’à ce que les conditions deviennent fausses ou tant
que les conditions sont vraies. Les instructions de la boucle sont exécutées au moins une fois.

N.B. : − L’instruction while(conditions) est suivie d’un point-virgule.

• Structure for

Syntaxe :
for(initialisations; conditions; incrémentations){
//ensemble d’instructions
}

Les instructions sont répétées tant que les conditions sont vraies. Les conditions sont
évaluées avant chaque itération de la boucle. Les initialisations sont effectuées avant
d’entrer dans la boucle pour la première fois. Les incrémentations sont exécutées après
chaque itération de la boucle.

N.B. : − Les trois paramètres de la boucle for sont à l’intérieur de parenthèses et sont
———— séparés par des points-virgules.
——— − Chaque instruction de la boucle for est terminée par un point-virgule.
——— − L’accolade n’est pas nécessaire que s’il y a plus d’une instruction.

• Structure foreach
La boucle foreach (appelée for avancée) a été intégrée depuis Java 5. Cette boucle est
utilisée pour parcourir les tableaux ainsi que les collections d’objets.

Syntaxe :
for(type variable : tableau | collection){
//ensemble d’instructions
}
CHAPITRE 2. ÉLÉMENTS DE BASE DE JAVA 23

Exemple :
public class BoucleForeach {
public static void main(String[] args) {
String[] tabString = {‘‘Ali’’,‘‘Jamal’’,‘‘Meryam’’,‘‘Mohamed’’};
for(String s : tabString)
System.out.println(s);
}
}

2.2.3 Les instructions de saut


• Notion d’étiquette
N’importe quelle instruction peut être étiquetée. Une étiquette désigne le début d’un
bloc d’instructions entourées d’accolades.

Syntaxe :

nomEtiquette : {
//liste d’instructions;
}

En Java, une étiquette ne peut se trouver que juste avant une instruction itérative (ou
un switch). La raison de mettre une étiquette c’est lorsqu’on a l’intention de revenir au
bloc itératif (ou au switch).

• L’instruction break
L’instruction break termine une structure itérative (while, do while ou for) ou une
structure switch. L’instruction break termine directement la boucle en cours.

Syntaxe :

break [ nomEtiquette ];

Si l’instruction break est accompagnée d’une étiquette, c’est qu’il faut sortir de l’étiquette.
Le contrôle est alors passé à l’instruction qui suit l’instruction étiquetée.
CHAPITRE 2. ÉLÉMENTS DE BASE DE JAVA 24

Exemple :

public class TestBreak {


public static void main (String args [ ]) {
forBreak:
for(int i=0; i<10;i++) {
if (i==7)
break forBreak;
}
}
}

• L’instruction continue
L’instruction continue ne peut être rencontrée que dans les instructions itératives.
L’instruction continue termine l’itération en cours : la boucle continue à s’exécuter avec
l’itération suivante.
Dans le cas des boucles while et do while, l’exécution reprend avec l’évaluation de la
condition de contrôle.

Syntaxe :

continue [ nomEtiquette ];

Dans le cas de la boucle for, l’évaluation repend avec l’évaluation de l’enchaı̂nement.


Si l’instruction continue est accompagnée d’une étiquette, il doit s’agir de l’étiquette d’une
instruction itérative englobante (qui démarre alors l’itération suivante).
CHAPITRE 2. ÉLÉMENTS DE BASE DE JAVA 25

Exemple :

public class TestContinue {


public static void main (String args [ ]) {
int i;
System.out.println("Les nombres impairs");
for(int i=0; i<100;i++) {
if (i%2==0)
continue;
else
System.out.print(" "+i);
}
}
}
CHAPITRE 2. ÉLÉMENTS DE BASE DE JAVA 26

2.3 Exercices d’application

Exercice 2.1
Développer un programme qui permet de chercher 20 premiers entiers positifs qui sont
premiers. Un nombre est dit premier s’il n’est divisible que par 1 et lui-même.

Exercice 2.2 (Chiffrement de césar)


Le chiffrement de césar est un algorithme de chiffrement des messages très simple. Son
principe est le décalage des lettres de l’alphabet (substitution mono-alphabétique).

Figure 2.2: Chiffrement de césar

Les formules de chiffrement et de déchiffrement sont les suivantes :

• C = (L + K) mod 26
• L = (C − K) mod 26

−L représente l’indice de la position de la lettre du texte clair.


−C représente l’indice de la position de la lettre du texte chiffré.
−K représente la clé de chiffrement et de déchiffrement (le pas de décalage).

Remarque : on commence le calcul par 0, c-à-d l’indice de la lettre ‘A’ = 0 et ‘Z’ =


25.

1. Développer un programme en Java qui permet de chiffrer et de déchiffrer un message en


utilisant le chiffrement de César.

Exercice 2.3 (Attaque d’Al-Kindi)


En effet Abu Yusuf Al-Kindi découvre aux alentours du 9eme siècle, une méthode très
simple permettant de venir à bout du chiffre de César : l’attaque par analyse des fréquences.
Cette analyse des fréquences consiste à répertorier toutes les lettres du texte chiffré et
de comparer leur nombre avec les fréquences des lettres de la langue correspondante.
CHAPITRE 2. ÉLÉMENTS DE BASE DE JAVA 27

Figure 2.3: Fréquences des lettres en français

Ainsi, dans un texte chiffré en français, si une lettre apparaı̂t aux environs des 16%,
nous pourrons assimiler cette lettre à un E ; et ainsi de suite avec les autres lettre du texte
chiffré.
Soit le texte chiffré par l’algorithme de César ci-dessous :
Ctot xlm ng etgztzx inkxfxgm hkbxgmx hucxm. Xg xyyxm, ng ikhzktffx Ctot xlm
utlx vhfiexmxfxgm lnk exl hucxml. Xqvximx exl mrixl wx whggxxl yhgwtfxgmtnq,
mhnm xlm hucxm.

1. Développer un programme en Java qui permet de découvrir la clé de chiffrement utilisée.


2. Exploiter la méthode du programme de l’exercice 2.2 pour déchiffrer le texte.

Merci de m’envoyer le compte rendu de ces exercices (en binôme) à


kh.elmakkaoui@gmail.com avant la séance prochaine.
Chapitre 3

Programmation Orientée Objet

Java est un langage de programmation orienté objet (POO). Il fallait dire que la prin-
cipale caractéristique du langage Java est qu’il a été conçu directement comme un langage
de POO. Cette spécificité permet une meilleure lisibilité des programmes (une plus grande
organisation des lignes de code).

3.1 L’approche objet


L’approche orientée objet propose un regroupement de l’aspect statique (attributs)
et dynamique (méthodes). L’idée de base repose sur l’observation de la façon dont nous
procédons dans notre vie courante.
La POO consiste à modéliser un ensemble d’éléments d’une partie du monde réel en
un ensemble d’entités informatiques ; ces entités sont appelées objets. Il s’agit de données
informatiques regroupant les principales caractéristiques des éléments du monde réel.

Le principe de base de la POO consiste à :


− reproduire des éléments du monde réel par des données informatiques appelées objets.
− regrouper (ou encapsuler) au sein d’une même unité appelée classe des attributs et les
méthodes.
− contrôler l’accès aux attributs et aux méthodes de la classe qui peut avoir un niveau de
visibilité publique, privé ou autres.
− produire des programmes de plus en plus larges et complexes.
− réutiliser des méthodes déjà testées.

3.2 Les concepts de base de l’approche objet


L’approche objet se base sur quelques concepts qu’il faut définir afin de pouvoir les
implémenter en Java.

3.2.1 Objet
L’objet est un groupement des valeurs des attributs. Il utilise les méthodes proposées
par sa classe pour manipuler ces attributs.

Exemple : Soit un compte c caractérisé par son numéro, propriétaire et solde. Pour
c, nous pouvons déposer ou retirer un montant donné et afficher son solde.
28
CHAPITRE 3. PROGRAMMATION ORIENTÉE OBJET 29

Figure 3.1: Schéma d’un objet c du type Compte

3.2.2 Communication entre les objets


La communication entre les objets sa fait par le seul moyen : les messages.
Un message transporte l’information nécessaire aux demandes à satisfaire.
Un message contient :
− le nom de l’objet destinataire,
− l’énoncé de la demande,
− les paramètres nécessaires.

Un message est réalisé par l’exécution d’une méthode de la classe. Les paramètres du
message seront utilisés comme paramètres de la méthode lancée.

Exemple : Pour l’objet c du type Compte, soit un message m qui permet de déposer
un montant de 100 dirhams pour le profit de c. En effet, c est défini par un numéro de
compte égal à 2371113.

Figure 3.2: Schéma de communication d’un message vers un objet


CHAPITRE 3. PROGRAMMATION ORIENTÉE OBJET 30

Après l’exécution du message m sur l’objet c, cet objet va changer d’état en modifiant
son solde.

3.2.3 Encapsulation
L’encapsulation est un regroupement d’attributs et de méthodes au sein d’un objet en
dissimulant ces attributs au monde extérieur.
Parmi les avantages de l’encapsulation :
− une meilleure modularité : la communication entre objets est assurée par les traitements
définis pour l’objet.
− une meilleure sécurité : certaines parties de l’objet sont inaccessibles.
− une simplicité apparente pour l’utilisateur : il n’y aura pas d’impacts pour l’utilisateur
de l’objet si le contenu de ce dernier a été changé.

3.2.4 Classe et instanciation


Les classes sont les briques de base de beaucoup de langages orientés objets. Une classe
est constituée de données (appelées attributs) et de traitements (appelés méthodes).

Une classe représente un élément concret du monde réel (exemple : personne, rectangle,
etc). Les attributs d’une classe représentent ses caractéristiques (exemple : pour la classe
Personne, nous pourrons gérer les attributs nom, prenom, etc.) et les méthodes représentent
les opérations que nous pourrons effectuer sur les attributs (exemple : les informations
d’une personne peuvent être affichées, modifiées, etc.). La déclaration des attributs et des
méthodes peut apparaı̂tre dans n’importe quel ordre.

Les classes servent de moules pour créer directement des instances. L’instanciation est
la fabrication d’un objet particulier à partir d’une classe.
Un objet est alors une instance d’une classe.

Exemple : Pour la classe Compte, nous définirons les attributs numéro, propriétaire,
solde ainsi que les méthodes déposer, retirer et afficher.
CHAPITRE 3. PROGRAMMATION ORIENTÉE OBJET 31

Figure 3.3: Exemple d’instanciations de la classe Compte

3.2.5 Constructeur et Destructeur


Pour réaliser l’instanciation, il suffit d’utiliser le constructeur de la classe. Le déclenchement
de ce constructeur permet de créer un objet.
Pour supprimer un objet, il suffit d’utiliser le destructeur de la classe.

Un constructeur est une méthode particulière de la classe qui le contient. Il possède


le même nom que la classe. Les constructeurs n’ont de type de retour ; par définition, ils
retournent un objet de cette classe. Le constructeur a pour rôle d’initialiser et configurer
une instance de la classe correspondante.

Java s’occupe de la destruction des objets. En effet, un système de ramasse-miettes


balaye la mémoire périodiquement pour supprimer les objets non référencés. Néanmoins,
ceci n’empêche pas à avoir la possibilité de définir le destructeur pour une classe et l’utiliser
en cas de besoin.

3.2.6 Héritage
L’héritage est un principe propre à l’approche objet. Il permet de créer une nouvelle
classe à partir d’une classe existante.
Le nom d’héritage provient du fait que la classe dérivée (la classe nouvellement
créée) contient les attributs et les méthodes de sa classe mère (la classe dont elle dérive).
L’intérêt majeur de l’héritage est de pouvoir réutiliser ce qui a été déjà défini ( attributs
et méthodes) sans avoir besoin de le redéclarer. L’héritage est donc un mécanisme permet-
tant le partage des propriétés communes entre les classes tout en préservant leurs différences.
CHAPITRE 3. PROGRAMMATION ORIENTÉE OBJET 32

Avec ce moyen, la classe dérivée sera plus spécialisée par rapport à sa classe mère
par l’ajout de nouveaux attributs et méthodes. Nous créons alors une hiérarchie de classes
de plus en plus spécialisées.

a. Héritage simple
Il est possible de représenter, sous forme d’une hiérarchie de classes (parfois ap-
pelée arborescence de classes), la relation de parenté qui existe entre les différentes
classes. L’arborescence commence par une classe générale appelée superclasse (appelée
aussi classe de base, classe parent, classe anc^ etre ou classe mère). Puis, les classes
dérivées (appelées aussi classes filles ou sous-classes) deviennent de plus en plus
spécialisées.
Ainsi, nous pouvons exprimer la relation qui lie une classe dérivée et sa superclasse
par l’association ‘est un’ représentée par une flèche de la classe dérivée vers la classe
mère.

Exemple :

Figure 3.4: Schéma d’héritage entre les classes Personne et Enseignant

Pour la classe Personne, nous pouvons définir les attributs nom, prenom et age ainsi
que la méthode afficher. Nous pouvons aussi définir une autre classe Enseignant qui
a les mêmes caractéristiques que celles d’une personne auxquelles nous ajoutons les attri-
buts specialite et matiere enseignée. La classe Enseignant est donc une extension et
spécialisation de la classe Personne puisqu’elle réutilise le contenu de la classe Personne.

a. Héritage multiple
Certains langages orientés objets permettent de faire de l’héritage multiple. Ce qui
signifie qu’ils offrent la possibilité de faire hériter une classe de deux classes mères. Ainsi,
cette technique permet de regrouper au sein d’une seule et même classe des attributs et des
méthodes hérités de plusieurs classes mères.
CHAPITRE 3. PROGRAMMATION ORIENTÉE OBJET 33

Le langage Java ne permet pas ce type d’héritage multiple ; il le remplace par la notion
d’interface (chap. 5).

3.2.7 Polymorphisme
Littéralement, le polymorphisme désigne la possibilité à prendre plusieurs formes (comme
l’eau qui se trouve à l’état solide, liquide ou gazeux). Cette propriété se conjugue avec
l’héritage pour produire des liens entre les objets.

3.3 Implémentation en Java


Les concepts orientés objets déjà présentés dans la section précédente. Dans cette sec-
tion, nous définirons leurs principes de fonctionnement et syntaxes d’utilisation en Java.

3.3.1 Les classes


a. Définition des paquetages
Lorsque plusieurs classes sont fortement corrélées entre elles, il est préférable de les
regrouper au sein d’un paquetage. Un paquetage ressemble beaucoup à la notion d’un
répertoire.
L’intérêt de la définition d’un paquetage est de fournir une plus grande facilité de
communication pour les classes qui se trouvent à l’intérieur du même paquetage.
Les paquetages ne sont pas des structures physiques. Ils n’existent que logiquement pour
regrouper une ou plusieurs classes.
Lorsque nous désirons inclure une classe dans un paquetage, nous utilisons au début du
fichier source de la classe le mot-clé package suivi du nom du paquetage.

Syntaxe :

package nompaquetage;

Les classes qui font partie d’un paquetage particulier ont accès à toutes les autres classes
qui font partie du même paquetage.

b. Définition d’une classe


Les classes constituent le concept de base de la programmation objet. Chaque classe
dispose d’un droit d’accès. Il permet de décider comment les autres classes qui peuvent
l’utiliser. Il est simplement défini par la présence ou l’absence du mot-clé public :
− avec le mot-clé public, la classe est accessible à toutes les autres classes ;
− sans le mot-clé public, la classe n’est accessible qu’aux classes du même paquetage.
CHAPITRE 3. PROGRAMMATION ORIENTÉE OBJET 34

Syntaxe :

package exemplecours;
public [abstract] class NomClass {
// [ liste des attributs ]
// [ liste des méthodes ]
}

Une classe regroupe des attributs et des méthodes qui manipulent ces attributs.

c. Les attributs
Java autorise la manipulation des attributs d’une classe avec des degrés de protection
appelés modes de protection. Avec les modes de protections, il s’agit d’autoriser les accès
aux attributs ou les refuser. Ces modes sont au nombre de quatre qui sont :

• private : un attribut privé n’est accessible que par les méthodes internes de la même
classe.
• public : un attribut publique est accessible par toute méthode de la même classe ou
d’une autre classe.
• protected : un attribut protégé n’est accessible que par les méthodes de la classe qui l’a
déclaré ou d’une classe dérivée, ou d’une autre classe du même paquetage.
• aucun : par défaut, si aucune protection n’est indiquée, l’attribut sera accessible par la
classe qui l’a déclaré et les autres classes du même paquetage.

Syntaxe : La syntaxe complète de déclaration des attributs est la suivante

[private/public/protected] [static] [final] type nomAttribut[=valeur];

Cette syntaxe sera expliquée en détail au fur et à mesure où nous avançons dans le cours.
CHAPITRE 3. PROGRAMMATION ORIENTÉE OBJET 35

Exemple : Soit la déclaration des attributs de la


classe Personne suivante :

package exemplecours;
public class Personne {
// attributs
private String nom;
private String prenom;
private int age;
// méthodes
}

Les attributs nom, prenom et age sont des attributs privés. Ils ne sont accessibles que
par les méthodes de la même classe. L’accès à ces attributs n’est pas permis ; il faut que
l’on fournisse les méthodes permettant de manipuler ces attributs privés.

d. Les méthodes
Les méthodes sont des opérations applicables sur les objets d’une classe. La définition
d’une méthode se fait en définissant le corps de la méthode à l’intérieur de la classe.
Une méthode est définie par un nom et des éventuels paramètres. Le type de retour
est soit void (si la méthode ne retourne aucun résultat), soit un type primitif ou une
référence vers un objet.
Comme les attributs d’une classe, les méthodes doivent être qualifiées d’un mode de
protection. Chaque mode agit sur le droit d’utilisation de la méthode. Ces modes sont les
suivants :

• private : indique qu’il s’agit d’une méthode interne à la classe. Seules les méthodes
de la même classe peuvent l’invoquer (ou l’appeler).
• public : indique qu’il n’y a pas restriction d’accès. La méthode est visible en dehors de
la classe : elle peut être appelée par n’importe quelle autre classe.
• protected : indique que l’invocation de la méthode est autorisée par toutes les méthodes
des classes dérivées et par toutes les méthodes des classes du même paquetage.
• aucun : si aucune protection n’est indiquée, la méthode pourra alors être invoquée par
les classes du même paquetage.

Syntaxe : La syntaxe complète de déclaration des méthodes est la suivante

[private/public/protected] [abstract] [static] [final] void/type


nomMéthode([paramètres]){
// le corps
}
CHAPITRE 3. PROGRAMMATION ORIENTÉE OBJET 36

Exemple : Soit la définition de la classe Personne suivante :

package exemplecours;
public class Personne {
// attributs
private String nom;
private String prenom;
private int age;
// méthodes
public void afficher() {
System.out.println(nom+","+prenom+","+age);
}
}

Les méthodes d’une classe peuvent être :


− des modificateurs (setters) permettant de changer la valeur d’un ou plusieurs attri-
buts d’un objet. Généralement, elles sont préfixées par set (exemple : setAge).
− des accesseurs (getters) permettant de retourner la valeur d’un attribut. Généralement,
elles sont préfixées par get (exemple : getAge).
− des constructeurs permettant d’initialiser les attributs de la classe. Le constructeur est
appelé lors de la création d’un objet.
− des méthodes qui effectuent des traitements spécifiques (comme : afficher(), ...).

Exemple :

package exemplecours;
public class Personne {
// attributs
private String nom;
private String prenom;
private int age;
// méthodes
public void setAge(int a) {
age = a;
}
public int getAge() {
return age;
}
}
CHAPITRE 3. PROGRAMMATION ORIENTÉE OBJET 37

e. Surcharge des méthodes


Dans une même classe, plusieurs méthodes peuvent avoir des noms identiques. Ces
méthodes doivent se distinguer par le nombre et/ou type des paramètres. À l’appel d’une
méthode de ce type, le compilateur se charge de déterminer l’appel convenable suivant le
nombre et/ou le type des paramètres de la méthode. Ce principe est appelé surcharge.

f. Le constructeur d’objets
Un constructeur est une méthode particulière qui est invoquée pour initialiser les attri-
buts d’une classe. Lorsqu’un nouvel objet est créé, Java lui alloue de la mémoire et initialise
ses attributs avec leurs valeurs par défaut. Puis, il appelle le constructeur associé à la classe
pour effectuer toutes les initialisations nécessaires.

Le constructeur d’objets se reconnaı̂t par les caractéristiques suivantes :


− il s’agit d’une méthode ayant le même nom que sa classe,
− il n’admet pas de types de retour,
− il peut avoir ou non des paramètres,
− il est invoqué implicitement lors de l’allocation de mémoire.

Généralement, nous pouvons avoir :


− un constructeur par défaut qui est généré automatiquement par le système, s’il
n’existe aucun autre constructeur dans la définition de la classe. Il permet d’initialiser
les attributs par des valeurs par défaut selon leurs types.
− un constructeur sans paramètres pour initialiser les attributs par des valeurs choi-
sies par le programmeur.
− des constructeurs avec paramètres pour initialiser les attributs par les valeurs données
en paramètres.
− un constructeur de copie qui prend en paramètre un objet de type de la classe elle-
même pour copier les valeurs des attributs de l’objet données en paramètre dans les attributs
correspondants de l’objet à créer.
CHAPITRE 3. PROGRAMMATION ORIENTÉE OBJET 38

Exemple :

package exemplecours;
public class Personne {
// Attributs
private String nom, prenom;
private int age;
// Constructeur sans paramètres
public Personne() {
nom = null;
prenom = null;
age = 20;
}
// Constructeur avec deux paramètres
public Personne(String n, String p) {
nom = n;
prenom = p;
age = 0;
}
// Constructeur avec trois paramètres
public Personne(String n, String p, int a) {
nom = n;
prenom = p;
age = a;
}
// Constructeur de copie
public Personne(Personne p) {
nom = p.nom;
prenom = p.prenom;
age = p.age;
}
public void afficher() {
System.out.println(nom+","+prenom+","+age);
}
}

En Java, on n’a pas à se soucier de la restitution de l’espace mémoire occupé par un


objet qui n’est plus référencé. En effet, un processus spécial de la JVM (appelé ramasse-
miettes) est activé pour récupérer la mémoire automatiquement. Par défaut, ce système
tourne en arrière-plan pendant l’exécution des programmes. Il repère les objets qui ne sont
plus référencés et libère l’espace mémoire alloué à ceux-ci.
Il est possible de désactiver le ramasse-miettes en utilisant l’option -noasyngc sur la
ligne de commande de lancement de la JVM.
CHAPITRE 3. PROGRAMMATION ORIENTÉE OBJET 39

3.3.2 Instanciation des objets


a. Les références d’objets
Un objet est une instance d’une classe. En Java, nous ne pouvons accéder aux objets
qu’à travers une référence vers celui-ci. Une référence est, en quelque sorte, ‘un pointeur’
vers une structure de données. Ce pointeur est représenté par une adresse mémoire qui sera
mise dans la référence.
Une variable de type référence vers un objet est utilisée pour stocker une référence vers
un objet. Nous ne pouvons pas connaı̂tre la valeur de la référence et nous ne pouvons
pas effectuer des opérations arithmétiques sur les références. La seule chose permise est de
changer la référence vers un autre objet.
Lorsqu’une variable de type référence est déclarée pour la première fois, et si elle n’est
pas assignée à aucune instance de classe, elle reçoit la valeur par défaut null. Cette valeur,
assignée à une référence, indique qu’il n’existe pas un objet pointé par cette référence.

b. Création des objets


Les attributs définis dans une classe sont appelés attributs d’instances. Les valeurs
de ces attributs diffèrent d’un objet à un autre. Les valeurs de ces attributs doivent être
affectées dès la création de l’objet. Si nous n’initialisons pas un attribut d’instance lors
de la création de l’objet, une valeur par défaut sera lui affectée en fonction de son type.

la déclaration d’un objet ne crée pas l’objet, mais crée uniquement une variable qui
référence cet objet. Toutefois, il est nécessaire de créer l’objet dynamiquement en utilisant
le mot-clé new. L’opérateur new est l’opérateur d’instanciation (ou création) des objets. La
déclaration et la création d’un objet sont deux étapes distinctes.

Syntaxe :

// déclaration d’un objet


[final] NomClasse nomObjet;
// création d’un objet
nomObjet = new NomClasse ([p1, p2, ... , pn]);
// déclaration et création d’un objet
[final] NomClasse nomObjet = new NomClasse ([p1, p2, ... , pn]);

− En Java, la création des objets figure dans la méthode main. Le fichier contenant la
main sera alors un programme de test pour tester la manipulation des objets créés.
− Un objet, déclaré avec l’opérateur final et qui référence un objet, ne peut pas
modifier sa référence vers un autre objet.
CHAPITRE 3. PROGRAMMATION ORIENTÉE OBJET 40

Exemple :

package exemplecours;
public class TestPersonne {
public static void main (String args [ ]) {
Personne p1;
p1 = new Personne ("Touil", "Abdelali",23);
final Personne p2 = new Personne ("ElMrabet", "Amine",25);
p2=p1; // erreur de compilation
}
}

3.3.3 Appel des méthodes


Les méthodes définies dans une classe sont des méthodes d’instances. Une méthode
d’instance est appelée par une instance de la classe.

Syntaxe :

nomObjet.nomMéthode([paramètres]);

Cet appel permet d’envoyer un message à l’objet utilisé pour exécuter la méthode
déclenchée sur les attributs de cet objet. Ceci entraı̂ne éventuellement des modifications
des valeurs des attributs de l’objet.

Exemple :

package exemplecours;
public class TestPersonne {
public static void main (String args [ ]) {
Personne p1;
p1 = new Personne ("Touil", "Abdelali",23);
Personne p2 = new Personne ("ElMrabet", "Amine",25);
p1.afficher();
p2.afficher();
}
}
CHAPITRE 3. PROGRAMMATION ORIENTÉE OBJET 41

3.3.4 La référence sur l’objet courant


a. Exemple introductif
Pour le constructeur de la classe Personne suivante :

public Personne (String nom, String prenom, int age) {


nom=nom;
prenom=prenom;
age=age;
}

il est logique d’écrire ces affectations en espérant que les membres gauches sont des attributs
de l’objet, et ceux de droite les paramètres du constructeur.
Au niveau de la compilation, ceci est acceptable. Mais au niveau de l’exécution, Java
n’est pas capable de distinguer entre ces identificateurs.
Il faut alors utiliser l’autoréférence this qui représente l’objet courant. Le constructeur
pourra alors être comme suit :

public Personne (String nom, String prenom, int age) {


this.nom=nom;
this.prenom=prenom;
this.age=age;
}

Nous interprétons alors this.nom comme le nom de la personne courante.

b. Définition
L’identificateur spécial this correspond à l’objet en cours de manipulation. Il est sou-
vent appelé la référence this ou autoréférence. Nous pourrons l’utiliser bien souvent
pour faire explicitement référence à l’instance de la classe courante.

Un constructeur peut appeler d’autres constructeurs surchargés dans sa classe en uti-


lisant la référence this avec des éventuels paramètres pour sélectionner le constructeur
désiré.
CHAPITRE 3. PROGRAMMATION ORIENTÉE OBJET 42

Exemple:
//Premier constructeur
public Personne (String nom, String prenom, int age) {
this.nom=nom;
this.prenom=prenom;
this.age=age;
} //Deuxième constructeur
public Personne (String nom, String prenom) {
this (nom, prenom, 0);
//D’autres éventuels traitements
}

L’avantage de l’appel du constructeur à l’intérieur d’un autre constructeur est que


nous avons un seul constructeur qui effectue toutes les initialisations de base. Les autres
constructeurs se contentent de l’utiliser pour ajouter d’autres traitements jugés utiles au
moment de la construction des objets.

3.3.5 Les membres statiques


a. Les attributs statiques
Lorsqu’un attribut est précédé par le mot-clé static dans sa déclaration, il sera un
attribut de classe. C’est-à-dire que tous les objets de la classe utiliseront la même valeur
de l’attribut : il est alors partagé par l’ensemble des objets.
Contrairement aux attributs d’instances (qui sont initialisés dans les constructeurs), un
attribut de classe doit être initialisé dès sa déclaration dans la classe ; sa valeur peut être
incrémentée dans les constructeurs.

Syntaxe :

[private/public/protected] static [final] type nomAttribut[=valeur];


CHAPITRE 3. PROGRAMMATION ORIENTÉE OBJET 43

Exemple : Pour la classe Personne, nous pourrons ajouter un attribut statique


nbPersonne qui compte le nombre de personnes créées.

package exemplecours;
public class Personne {
// attributs
private String nom;
private String prenom;
private int age;
private static int nbPersonne=0;
// Constructeur
public Personne(String nom, String prenom, int age){
this.nom=nom;
this.prenom=prenom;
this.age=age;
nbPersonne++;
}
}

Nous utilisons, généralement, d’attributs de classe pour stocker une information qui ne
dépend pas d’une instance particulière de la classe.
Nous accédons aux attributs statiques de la même manière que pour les attributs de
l’instance.
Toutefois, bien que les attributs statiques existent dans la classe, indépendamment de
l’instance, il est toujours possible d’y accéder directement via la classe. Nous pouvons alors
utiliser le nom de la classe comme référence. Cette opération provoque la modification de
la valeur du membre statique dans n’importe quelle instance existante et dans les instances
qui seront éventuellement créées.

Exemple :

Personne.nbPersonne=19;

Nous pouvons ajouter le mot-clé static pour les constantes. Cette valeur sera utilisée
par toutes les instances de la classe.
CHAPITRE 3. PROGRAMMATION ORIENTÉE OBJET 44

Exemple : Pour la classe Personne, nous pouvons définir la constante NB MODULE MAX
qui représente le nombre des modules maximaux pour chaque étudiant par semestre
et qui sera fixé à 8.

package exemplecours;
public class Personne {
// attributs
//...
private static final int NB MODULE MAX=8;
//...
}

b. Les méthodes statiques


Les méthodes qui ne portent pas le mot-clé static sont appelées des méthodes d’instance,
par contre, une méthode de classe est une méthode déclarée avec le modificateur static.
Comme les attributs statiques, les méthodes statiques appartiennent à la classe et non
à une instance particulière de la classe.
Une méthode statique ne peut utiliser que les attributs et méthodes statiques de sa
classe, sinon une erreur de compilation est générée.

Syntaxe :
[private/public/protected] static void/type nomMethode([parametres]){
//Définition de la méthode
}

Une méthode de classe est une méthode qui n’implémente pas un message envoyé à un
objet, mais qui définit un comportement global au niveau de la classe. En particulier, il n’y
a pas d’objets qui déclenchent une méthode de classe. L’appel d’une méthode statique doit
alors se faire avec le nom de sa classe.

Syntaxe :
NomClasse.nomMethode([parametres]);
CHAPITRE 3. PROGRAMMATION ORIENTÉE OBJET 45

Une méthode statique ne peut pas :


− faire référence, dans son corps, à l’objet courant this.
− être redéfinie dans les classes dérivées.

Exemple : la méthode afficherNbPersonne() déclarée dans la classe Personne est une


méthode statique.

package exemplecours;
public class Personne {
// attributs
private String nom;
private String prenom;
private int age;
private static int nbPersonne=0;
// Constructeur
public Personne(String nom, String prenom, int age){
this.nom=nom;
this.prenom=prenom;
this.age=age;
nbPersonne++;
}
public static void afficherNbPersonne(){
System.out.println("le nombre de personnes est:"+nbPersonne);
}
}

package exemplecours;
public class TestPersonne {
public static void main (String args[]){
// ...
Personne.afficherNbPersonne();
}
}

3.3.6 Les tableaux


Un tableau est un type particulier d’objets qui peut gérer une liste d’éléments consécutifs.
Le type des éléments d’un tableau est appelé le type de base du tableau. Le nombre
d’éléments gérés est un attribut fixé appelé taille du tableau.
CHAPITRE 3. PROGRAMMATION ORIENTÉE OBJET 46

L’accès aux valeurs d’un tableau se fait à l’aide d’un indice (du type entier), partant de
zéro jusqu’à la valeur nombre d’éléments diminués de un.
Les tableaux en Java sont des vrais objets. Un tableau est une instance d’une classe
tableau Java et possède un type correspondant dans le système de typage. Cela signifie que
pour utiliser un tableau comme un autre objet, nous devons déclarer en premier lieu une
variable du type approprié, puis nous utilisons l’opérateur new pour créer une instance.

a. Caractéristiques
En Java, les objets tableaux diffèrent des autres objets sur trois points :
• Java crée implicitement une classe spéciale tableau au moment de la déclaration d’une
nouvelle variable de type tableau.
• Java permet d’utiliser l’opérateur spécial [] pour accéder aux éléments du tableau.
• Java fournit une forme spéciale de l’opérateur new qui permet de construire une instance
d’un tableau en spécifiant sa taille avec la notation [].

b. Déclaration
Un objet de type tableau est caractérisé par un type de base suivi par des crochets vides
[]. Les crochets indiquent qu’il s’agit d’un tableau.

Syntaxe : les deux déclarations suivantes sont équivalentes :

[final] type nomTableau[];


[final] type[] nomTableau;

Dans chacun de ces cas, la taille du tableau n’est pas spécifiée, car il s’agit de déclarer
uniquement le type de l’objet. La déclaration permet uniquement de créer un objet de type
référence (initialisé par défaut à null) qui pourra référencer un tableau ultérieurement.
,→ Un tableau, déclaré avec l’opérateur final et qui contient un ensemble d’objets, ne peut
pas modifier son contenu.

c. Création et initialisation
Avec la déclaration d’un tableau, aucun espace mémoire n’est réservé. Il faut alors
réserver de l’espace mémoire nécessaire et signaler le nombre d’éléments que le tableau
contiendra. Ceci est fait avec l’opérateur new pour créer une instance du tableau. Après
new, il faut spécifier le type de base du tableau ainsi que sa taille entre des crochets. L’espace
mémoire sera alors contigu, et il ne sera plus question ensuite de modifier sa taille.
CHAPITRE 3. PROGRAMMATION ORIENTÉE OBJET 47

Syntaxe :

nomTableau[] = new type [taille];

Cette écriture permet d’allouer l’espace nécessaire pour les éléments du tableau dont le
nombre est donné par la variable taille. Ensuite, les éléments du tableau sont initialisés
systématiquement par la valeur par défaut de leur type.

Nous pourrons déclarer et initialiser un tableau avec la même instruction comme suit :

Syntaxe :

[fianl] type nomTableau[] = new type [taille];

Exemple :

float tableau[] = new float [19];

Java permet l’utilisation des accolades {} pour créer un tableau et initialiser ses éléments
au moment de leur déclaration. Dans ce cas nous n’utilisons pas l’opérateur new, et la taille
du tableau sera déduite à partir du nombre d’éléments affectés au tableau.

Syntaxe :

nomTableau[] = { valeur1, valeur2, ... };

La taille du tableau est récupérable avec le mot-clé length.

Syntaxe :

nomTableau.length;

Exercice : développer un programme qui calcule la moyenne d’un tableau.


CHAPITRE 3. PROGRAMMATION ORIENTÉE OBJET 48

3.3.7 Types des tableaux


Les éléments d’un tableau peuvent être :
− de type primitif (float, int, char, etc.).
− de type objet.
− ou des références de tableaux.

a. Tableaux de types primitifs


Le type des éléments est fixé à la déclaration. Lors de la création d’un tableau, tous
les éléments sont obligatoirement initialisés. Si l’initialisation n’est pas faite explicitement,
elle le sera implicitement par le système avec des valeurs par défaut (0 pour les nombres,
false pour les booléens, null pour les chaı̂nes de caractères, etc.).

Exemple :

int [] t1, t2[];


//t1 est un tableau à une seule dimension.
//t2 est un tableau à deux dimensions (ou matrice).

La manipulation d’un tableau Java peut être faite élément par élément (comme dans la
majorité des langages de programmation), ou en utilisant tout simplement la référence de
début du tableau.

package exemplecours;
public class Tableau {
public static void main (String args[]){
char [] t= new char[2];
t[0]= ‘K’;
t[1]= ‘M’;
System.out.print(t) ;
for(int i=0; i<t.length; i++);
System.out.print(t[i]) ;
}
}

b. Tableaux de types objets


En Java, un tableau d’objets ne contient que des références qui sont initialisées à null
jusqu’à ce qu’on leur a affecté des objets réels.
CHAPITRE 3. PROGRAMMATION ORIENTÉE OBJET 49

Pour manipuler les éléments d’un tableau d’objets, on doit respecter les trois étapes
suivantes :
− déclaration du tableau à manipuler ;
− création du tableau avec l’opérateur new ;
− remplissage du tableau.

Exemple: Nous pouvons créer un tableau d’objets comme suit


package exemplecours;
public class Tableau {
public static void main (String args[]){
//déclaration du tableau
Personne [] personnes;
//création du tableau
personnes = new Personne[20];
//remplissage du tableau
for(int i=0; i<t.length; i++);
personnes [i] = new Personne() ;
}
}

c. Tableaux de type références de tableaux


Les tableaux multidimensionnels sont des structures complexes possédant plusieurs in-
dices. Les dimensions dans ces tableaux sont des références vers de simples tableaux.

La déclaration de tels tableaux s’effectue en posant autant de crochets qu’il est nécessaire
à la suite de son type ou de son identificateur.

Syntaxe: Les deux déclarations suivantes sont équivalentes

type[][]... nomTableau;
type nomTableau [][]...;

La définition des tailles d’un tableau multidimensionnel utilise l’opérateur new.

Syntaxe:

nomTableau = new type[taille1][taille2]...;


CHAPITRE 3. PROGRAMMATION ORIENTÉE OBJET 50

L’initialisation d’un tableau multidimensionnel peut utiliser les accolades imbriquées.

Syntaxe: Tableau à trois dimensions

nomTableau [][][]= {{valeur, ...}, {valeur, ...}, {valeur, ...}};


CHAPITRE 3. PROGRAMMATION ORIENTÉE OBJET 51

3.4 Exercices d’application

Exercice 3.1
Un point est caractérisé par les attributs abscisse, ordonnée et couleur. Les méthodes
qui peuvent être associées à un point sont :
− initialiser : pour initialiser les attributs d’un point par des valeurs données en pa-
ramètres.
− deplacer : pour déplacer un point.
− afficher : pour afficher les attributs d’un point.
1. Trouver un type approprié pour un point.
2. Implémenter les méthodes demandées.
3. Implémenter la classe TestPoint qui permet de tester les méthodes proposées.

Exercice 3.2
RSA est un cryptosystème asymétrique peut-être utilisé à la fois pour les signatures électroniques
et pour le chiffrement. Il tire sa sécurité de la difficulté de factoriser des grands nombres.
La génération des clés :
− Générer deux nombres premiers aléatoires distincts p et q.
− Calculer n = pq.
− Calculer φ(n) = (p − 1)(q − 1).
− Sélectionner un exposant public e tel que pgcd(e, φ(n)) = 1.
− Calculer d ≡ e−1 (mod φ(n)).
,→ La clé publique est : (n, e). La clé privée est : (n, d).
Le chiffrement : Soit un message m, tel que m < n et (n, e).
− Calculer c = me (mod n).
,→ Le message chiffré : c.
Le déchiffrement : c et (n, d).
− Calculer m = cd ( mod n).
,→ Le message clair : m.

Développez un programme en Java qui permet de chiffrer et de déchiffrer en utilisant


le cryptosystème RSA.
1. Soient (n = 551, e = 5) et (d = 101). Implémentez la classe TestRSA qui teste les
méthodes proposées.
2. Affichez le temps de chiffrement et de déchiffrement.
3. Testez les méthodes proposées en utilisant des clés réelles.
Chapitre 4

Héritage et Polymorphisme

4.1 Héritage
4.1.1 Définition
L’héritage est une relation entre différentes classes permettant de définir de nouvelles
classes en se basant sur des classes existantes.
L’héritage est mis en œuvre par la construction de classes dérivées. Lorsqu’une classe B
hérite d’une classe A, nous disons que B est une classe dérivée (ou fille ou descendante)
de A. A est la superclasse (ou classe mère ou classe de base ou classe anc^ etre) de
B.
L’héritage est représenté par une flèche allant de la classe dérivée vers la classe
mère. Cette flèche indique que la classe fille hérite de la classe mère. Nous disons
que les deux classes sont reliées entre elles par un lien d’héritage ou une hiérarchie
d’héritage. La représentation schématique pourra être comme suit :

Figure 4.1: Représentation schématique de l’héritage entre deux classes A et B


L’emploi de l’héritage conduit à un style de programmation par raffinements succes-
sifs des classes. En effet, une classe dérivée modélise une extension d’une classe mère en
l’enrichissant par des informations supplémentaires.
La classe fille possède les caractéristiques suivantes :
• elle hérite les attributs de sa classe mère ;
• elle possède éventuellement de nouveaux attributs ;
• elle hérite les méthodes de sa classe mère ;
• elle redéfinit éventuellement certaines méthodes de sa classe mère ;
• elle possède éventuellement de nouvelles méthodes.

Nous aurons donc un objet du type classe mère contenu à l’intérieur d’un objet du
type classe fille.
Exemple : Un Etudiant est un cas particulier d’une Personne. Le digramme de classes
correspondant aux deux classes peut être le suivant :
52
CHAPITRE 4. HÉRITAGE ET POLYMORPHISME 53

Figure 4.2: Diagramme de classes : Personne-Etudiant

Avec le principe de l’héritage, la classe Etudiant devient composée de l’attribut filiere


seulement, les autres attributs de Personne ne sont plus répétés.

4.1.2 Syntaxe de l’héritage


La syntaxe de l’héritage est définie comme suit :

public class NomClasseFille extends NomClasseMere {


...
}

Exemple : pour exprimer que la classe Etudiant hérite les propriétés de la classe
Personne, nous écrivons :

package exemplecours;
public class Etudiant extends Personne {
// Contenu de la classe Etudiant
}
CHAPITRE 4. HÉRITAGE ET POLYMORPHISME 54

4.1.3 Enchaı̂nement des constructeurs


Un constructeur de la classe dérivée commence toujours par invoquer le construc
-teur de la classe mère. Cette invocation doit constituer la première instruction du
constructeur en utilisant le mot-clé super. L’invocation peut être accompagné par des pa-
ramètres si nous voulons appeler un constructeur avec paramètres, sinon il peut être fait
d’une manière implicite.
Ainsi, lors de la création d’un objet d’une classe dérivée, l’invocation des constructeurs
s’enchaı̂ne en commençant par le constructeur de plus haut niveau. Ceci entraı̂ne l’initiali-
sation de toutes les parties héritées de la classe mère, puis celles de la classe fille.

4.1.4 Propriétés des constructeurs


a. Invocation implicite du constructeur de la classe mère
Dans certains cas, il est possible de ne pas invoquer le constructeur de la classe mère.
Cette invocation sera opérée automatiquement par Java au moyen de l’instruction super().
Cette omission est possible uniquement si la classe mère possède un constructeur sans
paramètres ou si elle ne possède pas de constructeurs.

Exemple :
package exemplecours;
public class Etudiant extends Personne {
// Attributs
private String filiere;
// Constructeur sans paramètres
public Etudiant() {
super(); // instruction facultative
filiere = "SMI";
}
//methodes
}

L’instruction super() n’est pas obligatoire car elle peut être implicite.

b. Invocation explicite du constructeur de la classe mère


Parfois, il est nécessaire d’opérer une invocation explicite du constructeur lui permettant
de préciser les valeurs de ses paramètres. Le compilateur vérifie le type et le nombre de ces
paramètres.
Exemple : la classe Etudiant va ajouter à la classe Personne :
− un attribut filiere qui est le nom de la filière de l’étudiant.
− un nouveau constructeur permettant d’initialiser tous les attributs d’un étudiant.
CHAPITRE 4. HÉRITAGE ET POLYMORPHISME 55

package exemplecours;
public class Etudiant extends Personne {
// Attributs
private String filiere;
// Constructeur avec paramètres
public Etudiant(String nom, String prenom, int age, String filiere)
{
super(nom, prenom, age);
this.filiere = filiere;
}
//methodes
}

L’instruction super(nom, prenom, age) est un appel au constructeur de la classe mère


Personne. Nous savons que ce constructeur initialise les attributs nom, prénom et age de
l’objet Personne contenu à l’intérieur de l’objet Etudiant.

c. Le constructeur généré par le système


Si une classe fille ne contient aucun constructeur, le compilateur génère automatique-
ment un constructeur par défaut. Ce constructeur doit invoquer le constructeur sans pa-
ramètres (ou par défaut) de la classe mère et initialiser les attributs de la classe fille par
des valeurs par défaut (selon leurs types).

Pour une classe fille, la génération automatique d’un constructeur par défaut n’est
possible que si la classe mère :
− dispose d’un constructeur sans paramètres.
− ou ne dispose aucun constructeur.
,→ Si la classe mère ne contient que des constructeurs avec paramètres, le compilateur
génère une erreur.

4.1.5 Redéfinition des méthodes


La redéfinition d’une méthode consiste à reprendre la définition d’une méthode au
niveau d’une classe fille pour lui donner une nouvelle implémentation.
Soient deux classes A et B dont B hérite de A. S’il existe deux méthodes du même nom
respectivement dans les classes A et B, et si le nombre et le type des paramètres sont les
mêmes, il s’agit bien d’une redéfinition de méthode.

,→ Pour une méthode redéfinie, il est interdit d’avoir les mêmes paramètres avec un
type retourné des méthodes différentes pour éviter le risque d’ambiguı̈té.
,→ Une redéfinition ne doit pas modifier le comportement logique d’une méthode.
Elle peut éventuellement enrichir ce comportement, mais pas l’appauvrir.
CHAPITRE 4. HÉRITAGE ET POLYMORPHISME 56

4.1.6 Les modes de protection


L’unité de protection est la classe. Tous les objets de la même classe bénéficient de la
même protection. Les modes de protection peuvent concerner aussi bien les attributs que
les méthodes. Ces modes sont au nombre de quatre qui sont les suivants :

a. Le mode privé
Un attribut privé déclaré dans une classe mère sera hérité dans le sens où il occu-
pera une zone mémoire chez toutes les instances de la classe dérivée. Toutefois, sa valeur
ne sera pas accessible aux méthodes de la classe fille.
Une méthode privée ne peut pas être redéfinie dans une classe fille. La classe
fille peut proposer une méthode portant le même nom et les mêmes paramètres, mais cette
méthode n’aura rien à voir avec la méthode privée de la classe mère.

b. Le mode publique
Les attributs publiques peuvent être hérités. Ils sont accessibles (uniquement par le
mot-clé super) directement par les méthodes de la classe dérivée.

Les méthodes publiques peuvent être héritées. De telles méthodes peuvent être redéfinies
dans la classe fille pour adapter leur comportement. Dans ce ces, si une méthode de la classe
fille désire invoquer la méthode de la classe mère, elle pourra le faire en utilisant le mot-clé
super.

c. Le mode protégé
Le mode protégé (appelé protected) autorise l’accès aux classes dérivées et du
m^
eme paquetage.

Les attributs et les méthodes protégés sont hérités, et sont accessibles par :
− les méthodes de toutes les classes dérivées ;
− et les méthodes de toutes les classes appartenant au même paquetage. En Java, nous
considérons que les classes du même paquetage sont vraiment des classes amies, au point
de faire partie de la même famille.

Une méthode protégée peut être redéfinie. Il est possible, au moment de sa redéfinition,
de modifier son mode de protection en passant du mode protégé au mode publique ; l’in-
verse n’est pas autorisé.

d. Le mode par défaut


Par défaut, si le mode de protection n’est pas précisé, le mode par défaut (appelé aussi
package) est pris en compte. Il s’agit d’un mode de protection spécifique au langage Java.
Les attributs et méthodes, ayant ce mode de protection, ne sont accessibles unique-
ment que pour les classes du m^ eme paquetage.
CHAPITRE 4. HÉRITAGE ET POLYMORPHISME 57

4.1.7 Portée des méthodes redéfinies


La redéfinition d’une méthode publique doit être publique, et la redéfinition
d’une méthode protégée sera elle-même protégée ou publique.
La redéfinition ne concerne pas une méthode privée.

Exemple :

package exemplecours;
public class Personne {
private String nom, prenom;
private int age;
public Personne (String nom, String prenom, int age) {
this.nom = nom;
this.prenom = prenom;
this.age = age;
}
public void afficher () {
System.out.print(nom+","+prenom+","+age);
}
}

package exemplecours;
public class Etudiant extends Personne {
//...
public void afficher () {
super.afficher();
System.out.println(","+filiere);
}
}

package exemplecours;
public class Test {
public static void main (String args[]) {
Etudiant e = new Etudiant ("BOUROUA","Issam",21,"SMI");
e.afficher();
}
}

La méthode afficher de la classe Etudiant s’appuie sur la méthode afficher de sa


classe mère (super.afficher()) pour afficher sa partie personne puis elle ajoute l’affichage
de l’attribut filiere qui est propre à la classe Etudiant.
CHAPITRE 4. HÉRITAGE ET POLYMORPHISME 58

La classe Etudiant dispose maintenant de deux méthodes afficher() :


− celle héritée de la classe mère Personne ;
− et la sienne.

4.1.8 Interdire la redéfinition et bloquer l’héritage


a. Les méthodes finales
Une méthode finale (déclarée avec le mot-clé final) est une méthode publique ou
protégée dont la redéfinition est interdite aux classes dérivées.

public/protected final type nomMethode() {


// Contenu de la méthode
}

Nous utilisons la finalisation pour deux raisons :


− Sécurité : nous pouvons faire confiance à l’implémentation d’une méthode finale. Le
comportement d’une telle méthode ne sera pas modifié quel que soit le type courant de
l’objet qui reçoit le message.
− Efficacité : lorsqu’une méthode non finale est invoquée, la recherche de la bonne
implémentation de la méthode doit être effectué pendant l’exécution . Ce n’est pas le cas
pour les méthodes finales.

b. Les classes finales


Une classe finale ne peut pas avoir des classes dérivées. Toutes ses méthodes
sont alors implicitement finales. Une classe finale est définie avec le modificateur final.

Syntaxe :
package nompaquetage;
public final class NomClasse {
// Contenu de la classe
}
CHAPITRE 4. HÉRITAGE ET POLYMORPHISME 59

4.2 Polymorphisme
4.2.1 Définition
Le nom polymorphisme vient du grec, ::::
appliqué sur un objet, signifie que cet objet
peut prendre plusieurs formes. Cette caractéristique est un des concepts essentiels de la
programmation orientée objet.
Alors que l’héritage concerne les classes, le polymorphisme est relatif aux méthodes
et objets.

Les objectifs principaux du polymorphisme sont :


− mémoriser facilement les noms des méthodes,
− permettre la liaison dynamique.

Nous distinguons généralement deux types de polymorphisme :


− Le polymorphisme des méthodes (avec surcharge ou avec redéfinition),
− Le polymorphisme des objets (liaison dynamique ou transtypage).

4.2.2 Le polymorphisme des méthodes


a. Le polymorphisme avec surcharge
Il représente la possibilité de définir, dans une même classe ou dans une classe dérivée,
plusieurs méthodes du même nom mais possédant des paramètres différents (en nombre
et/ou en types). Ce type de polymorphisme rend ainsi possible le choix automatique de
la bonne méthode à adopter en fonction du nombre et des types des données passées en
paramètre.

Exemple : Soit la classe Somme qui permet de faire la somme de deux valeurs. Nous pou-
vons définir plusieurs méthodes appelées additionner effectuant une somme de valeurs sur
des différents types de paramètres :

package exemplecours;
public class Somme {
private int a, b;
private float x, y;
//Constructeurs
public int additionner(int a, int b) {
return a+b
}
public float additionner(float x, float y) {
return x+y
}
}
CHAPITRE 4. HÉRITAGE ET POLYMORPHISME 60

Nous appelons signature d’une méthode le nombre et le type des paramètres. C’est
donc la signature d’une méthode qui détermine laquelle des méthodes surchargées sera
appelée.

b. Le polymorphisme avec redéfinition


La possibilité de redéfinir une méthode dans des classes dérivées d’une classe mère
s’appelle la spécialisation. Il est possible d’appeler la méthode d’un objet sans se soucier
de son type. Ceci permet de faire abstraction des détails des classes spécialisées, en les
masquant par une interface commune (qui est la classe mère).

4.2.3 Le polymorphisme des objets


a. La liaison dynamique
La liaison dynamique est la base de l’extensibilité dans la programmation objet et de
la maintenance des systèmes :
− de nouveau code (via des nouvelles classes) peut être introduit dynamiquement sans
même arrêter l’application qui tourne.
− ceci permet de remplacer un composant (un objet) par un autre.

Exemple : Si nous définissons deux classes Etudiant et Enseignant qui héritent de la


classe Personne. Dans le programme principal, nous pourrons avoir les deux instructions
suivantes :

Personne etu = new Etudiant ();


Enseignant ens = new Enseignant ();
//classe déclarée = type de la référence
//classe réelle = classe d’exécution

Le principe de la liaison dynamique est basé sur deux concepts :


− La classe réelle : elle n’est connue qu’à la construction réelle de l’objet.
− La classe déclarée : chaque objet doit être déclaré de type d’une classe donnée.

Le compilateur vérifie que la classe réelle hérite de la classe déclarée.


À l’exécution du programme, la classe réelle d’un objet peut correspondre à l’une ou
l’autre des classes appartenant à la hiérarchie associée à la classe déclarée.

Si deux méthodes dans la hiérarchie ont le même nom, Java exécute la première méthode
trouvée en partant de la classe réelle de l’objet et en remontant dans la hiérarchie des classes.

Comme le lien vers la méthode à exécuter est déterminé dynamiquement, nous parlons
alors de liaison dynamique.
CHAPITRE 4. HÉRITAGE ET POLYMORPHISME 61

À la phase de compilation, le système vérifie que toutes les déclarations sont correctes.
Par contre, à la phase d’exécution, il vérifie l’instanciation.

Exemple : Si nous disposons d’une classe ClasseB qui hérite d’une classe ClasseA,
l’instruction ClasseA a = new ClasseB() permet de déclarer un objet a du type ClasseA,
mais qui référence un objet du type ClasseB. Avec ce cas d’exemple, nous avons deux effets :
− L’instruction a.afficher() ne sera considérée comme correcte que si ClasseA possède
la méthode afficher().
− Si ClasseA possède une méthode afficher() qui affiche ”A” et ClasseB possède une
méthode afficher() qui affiche ”B”, alors le résultat de l’instruction a.afficher() est
”B” malgré que a est déclaré du type ClasseA.

b. Le transtypage explicite
Le transtypage explicite consiste à convertir une référence d’objet d’une certaine classe
en une référence d’objet d’une autre classe. Ceci n’est possible que si les classes sont reliées
par un lien d’héritage.

Le transtypage explicite est utilisé lorsqu’une référence d’un objet contient une instance
d’une classe dérivée, il est nécessaire de forcer le type de la référence pour accéder aux
attributs et méthodes spécifiques à la classe dérivée. Si ce n’est pas fait, le compilateur ne
peut déterminer le type réel de l’instance, ce qui provoque une erreur de compilation.

Syntaxe :
(NomClasse) nomObjet;

Avec la condition où la classe réelle de nomObjet doit hériter de NomClasse, sinon une
exception ClassCastException est levée (chapitre 6).

Exemple : Soit l’exemple de la classe Personne et sa fille Etudiant.

package exemplecours;
public class Etudiant extends Personne {
// ...
public String getFiliere() {
return filiere;
}
}
CHAPITRE 4. HÉRITAGE ET POLYMORPHISME 62

package exemplecours;
public class Test {
public static void main (String args[]) {
//Ligne1
Personne e = new Etudiant ("AZARFAN","Ali",21,"SMI");
//Ligne2: erreur de compilation
System.out.println(e.getFiliere());
//Ligne3: transtypage explicite
System.out.println(((Etudiant)e).getFiliere());
}
}

− avec la ligne Ligne1, c’est la liaison dynamique.


− avec la ligne Ligne2, pour le compilateur, la variable e est un objet de la classe Personne,
donc qui n’a pas de méthode getFiliere.
− avec la ligne Ligne3, nous forçons le type de la variable e (transtypage explicite) pour
pouvoir appeler la méthode getFiliere().

4.2.4 L’opérateur instanceof


L’opérateur instanceof permet de contrôler le type d’un objet.

Syntaxe :
nomObjet instanceof NomClasse

L’opérateur instanceof retourne true si :


− l’objet nomObjet est une instance de la classe NomClasse (créé par new NomClasse()).
− ou l’objet nomObjet est une instance d’une classe dérivée de la classe NomClasse.

Exemple : pour l’exemple de la classe Personne et sa dérivée Etudiant, nous pourrons


écrire la méthode main suivante :

package exemplecours;
public class Test {
public static void main (String args[]){
Personne p = new Personne();
Etudiant e = new Etudiant ("BENSAID", "Mohamed", 21, "SMI");
if (e instanceof Personne)
System.out.println("L’étudiant e est une personne");
else
System.out.println("Erreur");
}
}
CHAPITRE 4. HÉRITAGE ET POLYMORPHISME 63

4.2.5 Tableaux polymorphes


Un tableau polymorphe manipule des objets du types différents reliés par une hiérarchie
d’héritage.

Exemple : pour la hiérarchie Personne, Enseignant et Etudiant, nous pourrons définir


le code de la classe Test suivant :

package exemplecours;
public class Test {
public static void main (String args[]){
Personne p = new Personne();
Enseignant pr = new Enseignant ("BENALLA", "Hicham", 30, "Info");
Etudiant e = new Etudiant ("EL KHAYATI", "Samira", 21, "SMI");
Personne [] tab = new Personne;
tab [0] = p;
tab [1] = pr;
tab [2] = e;
for (int i=0; i<tab.length; i++)
tab[i].afficher()
}
}

Dans ce cas d’exemple, la structure tab est dite polymorphe puisqu’elle manipule des objets
différents de la hiérarchie.
CHAPITRE 4. HÉRITAGE ET POLYMORPHISME 64

4.3 Exercices d’application

Exercice 4.1
Soit le diagramme de classes suivant :

1. Implémenter les classes correspondant à ce diagramme.


2. Implémenter une classe Test.

Exercice 4.2
Soient les classes suivantes :
− Employe définie par les attributs nom, prénom, adresse, numéro CIN, matricule, date
d’embauche, salaire.
− EmployeAssure : un employé assuré se caractérise par les attributs numéro CNSS et date
d’inscription à la CNSS.
− EmployeNonAssure : c’est un employé non assuré.

Les attributs date d’embauche et date d’inscription à la CNSS sont du type Date.

Chaque classe possède le/les constructeurs (avec paramètres et/ou de copie) et la méthode
afficher().

Soit la classe Societe qui embauche des employés assurés et des employés non assurés.
Une société se caractérise par les attributs suivants : code, raison sociale et un tableau
d’employés recrutés.

Nous pouvons, pour une société afficher ses attributs, ajouter, rechercher et supprimer
des employés assurés et non assurés.

1. Implémenter les classes appropriées.


2. Implémenter la classe TestSociete.
Chapitre 5

Classes Abstraites et Interfaces

Java a supprimé la notion d’héritage multiple qui existe dans les notions de base de
l’orientée objet. Pour remplacer ce concept, Java propose les interfaces.

5.1 Les classes abstraites


Lors de la conception d’une hiérarchie, nous avons besoin de créer des classes plus
générales d’abord et différer l’implémentation à des étapes plus éloignées quand le com-
portement est très bien défini. Autrement dit, il pourra être nécessaire au programmeur de
créer une classe déclarant une méthode sans la définir. La définition de cette méthode est
laissée aux classes dérivées. Nous parlons alors de méthodes abstraites.

a. Méthode abstraite
Une méthode abstraite est une méthode qui n’a pas de corps d’instructions ; elle est
définie par son prototype seulement. Pour être acceptée par le compilateur, l’entête de cette
méthode doit comporter le mot-clé abstract.

Syntaxe:
public abstract type nomMethode ([parametres]);

L’avantage des méthodes abstraites est qu’elles peuvent déclarer un comportement glo-
bal (au niveau d’une classe mère) commun à un ensemble de classes dérivées dans une
hiérarchie d’héritage.

Une méthode non abstraite est dite concrète, elle contient le corps de sa définition.

b. Classe abstraite
Une classe peut être définie abstraite. Le mot-clé abstract, écrit avant le mot class,
annonce qu’il s’agit d’une classe abstraite.

Syntaxe:
package nompaquetage;
public abstract class NomClasse {
//Contenu de la classe
}
65
CHAPITRE 5. CLASSES ABSTRAITES ET INTERFACES 66

Si une classe qui contient au moins une méthode abstraite doit être alors définie abstraite.

Syntaxe:
package nompaquetage;
public abstract class NomClasse {
//...
public abstract type nomMethode1 ([parametres]);
public type nomMethode2 ([parametres]){
//Contenu de la méthode
}
}

Une classe abstraite doit respecter les contraintes suivantes :


− Une classe abstraite ne peut pas être instanciée. L’opérateur new sera donc interdit. Elle
ne pourra être instanciée qu’à travers ses classes dérivées.
− Une classe abstraite peut ne pas avoir des méthodes abstraites.
− Une classe qui hérite d’une classe abstraite doit implémenter toutes les méthodes abs-
traites de sa classe mère, sinon elle est aussi une classe abstraite.
− Une classe abstraite ne peut pas être déclarée comme final ou private.

,→ Une classe abstraite sert uniquement à définir un cadre général, c’est-à-dire à définir
l’ensemble des caractéristiques communes aux classes dérivées. Elle ne peut servir que de
classe mère pour une dérivation.

Exemple : Pour la classe Personne et ses dérivées, nous pourrons déclarer une méthode
abstraite calculer au niveau de la classe Personne et qui sera définie dans les classes
EnseignantPermanent et EnseignantContractuel selon les attributs de ces classes. Les
classes Personne et Enseignant restent alors abstraites puisqu’elles n’ont pas défini cette
méthode.
La méthode calculer permet de calculer le salaire d’enseignant. S’il s’agit d’un per-
manent, son salaire mensuel est égal au salaire de base auquel nous ajoutons le nombre
des heures supplémentaires multiplié par le prix d’une heure supplémentaire. S’il s’agit
d’un contractuel, son salaire correspond alors à la durée du contrat multipliée par le salaire
mensuel.
CHAPITRE 5. CLASSES ABSTRAITES ET INTERFACES 67

package exemplecours;
public abstract class Personne {
private String nom, prenom;
private int age;
public Personne (String nom, String prenom, int age){
this.nom=nom;
this.prenom=prenom;
this.age=age;
}
public abstract float calculer ();
public void afficher (){
System.out.print(nom+", "+prenom+", "+age) ;
}
}

La classe Personne contient la méthode calculer() qui est abstraite. La classe devient
alors abstraite.

package exemplecours;
public abstract class Enseignant extends Personne {
private String matiere;
public Enseignant (String nom, String prenom, int age, String
matiere){
super(nom, prenom, age);
this.matiere=matiere;
}
public void afficher (){
super.afficher ();
System.out.println(", "+matiere);
}
}

La classe Enseignant hérite de la classe Personne mais ne définit pas la méthode calculer() ;
elle reste alors abstraite.
CHAPITRE 5. CLASSES ABSTRAITES ET INTERFACES 68

package exemplecours;
public class EnseignantPermanent extends Enseignant {
private float salaireBase, prixHeureSupp;
private int nbHeureSupp;
public EnseignantPermanent (String nom, String prenom, int age,
String matiere, float salaireBase, float prixHeureSupp, int
nbHeureSupp){
super(nom, prenom, age, matiere);
this.salaireBase=salaireBase;
this.prixHeureSupp=prixHeureSupp;
this.nbHeureSupp=nbHeureSupp;
}
public float calculer (){
return salaireBase+(prixHeureSupp*nbHeureSupp);
}
public void afficher (){
super.afficher ();
System.out.println("Salaire de base "+salaireBase);
System.out.println(prixHeureSupp+" "+nbHeureSupp);
System.out.println("Montant mensuel à payer : "+ calculer ());
}
}
CHAPITRE 5. CLASSES ABSTRAITES ET INTERFACES 69

package exemplecours;
public class EnseignantContractuel extends Enseignant {
private int dureeContrat;
private float salaireMois;
public EnseignantContractuel (String nom, String prenom, int age,
String matiere, int dureeContrat, float salaireMois {
super(nom, prenom, age, matiere);
this.dureeContrat=dureeContrat;
this.salaireMois=salaireMois;
}
public float calculer (){
return dureeContrat*salaireMois;
}
public void afficher (){
super.afficher ();
System.out.println("Salaire de base "+salaireBase);
System.out.println(dureeContrat);
System.out.println("Montant total à payer : "+ calculer ());
}
}

Les classes EnseignantPermanent et EnseignantContractuel héritent de Enseignant


et elles définissent la méthode calculer() : elles seront alors concrètes.

package exemplecours;
public class Test {
public static void main (String args []){
//Personne et Enseignant sont abstraites: elles ne peuvent pas
e
^tre instanciées
EnseignantPermanent ep=new EnseignantPermanent ("Touil", "Ali",
31, "Informatique", 7000F, 4000F, 7);
ep.afficher();
EnseignantContractuel ec=new EnseignantContractuel ("ElMrabet",
"Amine", 33, "Informatique", 5, 6000F);
ec.afficher();
}

Le recours aux classes abstraites facilite largement la conception orientée objet. En


effet, nous pouvons placer dans une classe abstraite toutes les fonctionnalités dont nous
souhaitons disposer pour toutes les classes dérivées.
Une classe qui ne contient que des méthodes abstraites correspond plutôt à ce que
l’on appelle une interface.
CHAPITRE 5. CLASSES ABSTRAITES ET INTERFACES 70

5.2 Les interfaces


5.2.1 Définition et déclaration d’une interface
Le mécanisme d’interface est une généralisation du concept de classe abstraite.
L’interface définit, en quelque sorte, un contrat que certaines classes s’engagent à respecter
sans préciser les termes de ce contrat.
Les interfaces ne contiennent que des définitions de constantes et des prototypes de
méthodes abstraites. Il n’est pas nécessaire de spécifier que ces méthodes sont abstraites :
elles le sont implicitement.
La déclaration d’une interface se présente comme celle d’une classe. Nous utilisons
simplement le mot-clé interface à la place de class.

Syntaxe:
package nompaquetage;
interface NomInterface {
[liste des constantes;]
[liste de déclarations des méthodes;]
}

Le nom d’une interface doit respecter les mêmes conventions que celles d’une classe.
Une interface est par défaut abstraite et publique.
Les méthodes d’une interface sont par défaut publiques et abstraites.
Les constantes d’une interface sont par défaut publiques, statiques et finales.

Exemple:
package exemplecours;
interface Visualisation {
void afficher ();
}

5.2.2 Implémentation d’une interface


L’implémentation d’une interface se réalise grâce au mot-clé implements.

Syntaxe:
package nompaquetage;
public class NomClasse implements NomInterface {
//Attributs de la classe
//Définition des méthodes déclarées dans l’interface
//Définition des méthodes de la classe
}
CHAPITRE 5. CLASSES ABSTRAITES ET INTERFACES 71

Une classe qui implémente une interface et ne définit pas toutes les méthodes de
cette interface, sera une classe abstraite.
L’implémentation d’une interface peut être représentée par une flèche interrompue,
comme suit :

Figure 5.1: Schéma d’implémentation d’une interface

Exemple : la classe Personne peut implémenter l’interface Visualisation pour affi-


cher les informations de la personne.

package exemplecours;
public class Personne implements Visualisation {
private String nom, prenom;
private int age;
//Définition de la méthode de l’interface
public void afficher () {
System.out.println(nom+", "+prenom+", "+age);
}
//Définition des méthodes de la classe Personne
}

5.2.3 Implémentation de plusieurs interfaces


Une classe peut implémenter plusieurs interfaces. Elle doit forcément fournir le code
de toutes les méthodes de toutes les interfaces implémentées, sinon elle sera une classe
abstraite.
CHAPITRE 5. CLASSES ABSTRAITES ET INTERFACES 72

Syntaxe:
package nompaquetage;
public class NomClasse implements NomInterface1, NomInterface2, ... {
//Attibuts de la classe]
//Définition des méthodes déclarées dans toutes les interfaces
//Définition des méthodes de la classe
}

En Java, une classe ne peut hériter que d’une seule classe, mais une classe peut implémenter
plusieurs interfaces. C’est une solution pour simuler l’héritage multiple.

Si une classe implémente toutes les méthodes d’une interface, une instance de cette
classe peut être considérée et traitée comme un objet de type interface. Nous pourrons
alors lui appliquer l’opérateur instanceof pour vérifier qu’il représente une instance de
l’interface implémentée.

Exemple : pour l’exemple de la classe Personne et ses dérivées, nous pourrons utiliser
l’interface Visualisation pour afficher les informations des classes et l’interface Calcul
pour calculer les salaires des enseignants contractuels et permanents. Nous aurons les in-
terfaces et classes suivantes :
package exemplecours; package exemplecours;
interface Visualisation { interface Calcul {
void afficher (); float calculer ();
} }

package exemplecours;
public abstract class Personne implements Virtualisation, Calcul {
private String nom, prenom;
private int age;
public Personne (String nom, String prenom, int age) {
this.nom=nom;
this.prenom=prenom;
this.age=age;
}
public void afficher () {
System.out.print(nom+", "+prenom+", "+age) ;
}
}
CHAPITRE 5. CLASSES ABSTRAITES ET INTERFACES 73

package exemplecours;
public abstract class Enseignant extends Personne {
private String matiere;
public Enseignant (String nom, String prenom, int age, String
matiere){
super(nom, prenom, age);
this.matiere=matiere;
}
public void afficher (){
super.afficher ();
System.out.println(", "+matiere);
}
}

La classe Enseignant hérite de Personne mais n’a pas encore défini la méthode calculer
() ; elle reste alors abstraite.

package exemplecours;
public class EnseignantContractuel extends Enseignant {
private int dureeContrat;
private float salaireMois;
public EnseignantContractuel (String nom, String prenom, int age,
String matiere, int dureeContrat, float salaireMois {
super(nom, prenom, age, matiere);
this.dureeContrat=dureeContrat;
this.salaireMois=salaireMois;
}
public float calculer (){
return dureeContrat*salaireMois;
}
public void afficher (){
super.afficher ();
System.out.println(dureeContrat);
System.out.println(salaireMois);
}
}

La classe EnseignantContractuel arrive à définir toutes les méthodes des interfaces


implémentées par la classe Personne. EnseignantContractuel est alors concrète.
CHAPITRE 5. CLASSES ABSTRAITES ET INTERFACES 74

package exemplecours;
public class Test {
public static void main (String args []){
Visualisation ec1 = new EnseignantContractuel ("ElMrabet",
"Amine", 33, "Informatique", 5, 6000F);
ec1.afficher();
Calcul ec2 = new EnseignantContractuel ("ElMrabet", "Amine",
33, "Informatique", 5, 6000F);
System.out.println("le salaire est: "+ec2.calculer());
//ou
EnseignantContractuel ec = new EnseignantContractuel
("ElMrabet", "Amine", 33, "Informatique", 5, 6000F);
ec.afficher();
System.out.println("le salaire est: "+ec.calculer());
}
}

Il est possible de déclarer des références de type interfaces.


Il est interdit de construire des instances pour les interfaces, donc nous ne pouvons pas
utiliser l’opérateur new pour créer un objet de type interface.
Une référence interface ne peut utiliser que les méthodes déclarées dans l’interface.

5.2.4 Dérivation d’une interface


Une interface peut hériter d’une autre interface. Le principe de l’héritage entre les
interfaces respecte les mêmes contraintes de l’héritage entre les classes.

Exemple : Soit la hiérarchie d’interfaces suivante :

Figure 5.2: Schéma de dérivation de deux interfaces


CHAPITRE 5. CLASSES ABSTRAITES ET INTERFACES 75

Une classe qui implémente l’interface dérivée doit définir les méthodes des deux inter-
faces, sinon elle reste abstraite.
Une interface ne peut pas dériver d’une classe, seulement d’une autre interface.
CHAPITRE 5. CLASSES ABSTRAITES ET INTERFACES 76

Exercices d’application

Exercice 5.1
Soit le diagramme de classes suivant :

ElGamal est un cryptosystème asymétrique peut-être utilisé à la fois pour les signa-
tures électroniques et pour le chiffrement. Il tire sa sécurité de la difficulté de calculer des
logarithmes discrets.
La génération des clés :
− Choisir un nombre premier p.
− Générer le générateur g de groupe cyclique G d’ordre p.
− Choisir un nombre aléatoire x inférieur à p − 1.
− Calculer y = g x mod p.
,→ La clé publique est : (p, g, y). La clé privée est : (x).
Le chiffrement : Soit un message m, tel que m < p.
− Choisir un nombre aléatoire k inférieur à p − 1.
− Calculer c1 = g k mod p.
− Calculer c2 = m ∗ y k mod p.
,→ Le message chiffré : c = (c1 , c2 ).
Le déchiffrement :
(p−1)−x
− Calculer m = c2 ∗ c1 mod p.
,→ Le message clair : m.

1. Implémenter l’interface et les classes correspondant à ce diagramme.


2. Implémenter une classe Test.
CHAPITRE 5. CLASSES ABSTRAITES ET INTERFACES 77

Exercice 5.2
Soit le diagramme de classes suivant :

1. Implémenter la classe Habitant.


2. Implémenter l’interface Statique avec :
− getAgeMoyen() permet de calculer l’âge moyen de tous les habitants d’une ville ou d’un
pays. L’âge moyen pour un pays est la moyenne de tous les âges moyens des villes qui le
composent.
− getNbHabitant retourne le nombre d’habitants d’une ville ou d’un pays.
− getSurface() retourne la surface d’une ville ou d’un pays. La surface d’un pays est la
somme des surfaces de toutes les villes qui le composent.
3. Implémenter la classe Ville. Cette classe contient un tableau d’habitants dont la taille
maximale est NB MAX.
4. Implémenter la classe Capitale. L’attribut catégorie qui peut avoir les valeurs ”poli-
tique”, ”économique” ou ”politique et économique”.
5. Implémenter la classe Pays avec :
− la méthode afficherVilles() permet d’afficher les noms de toutes les villes du pays
sauf la capitale.
− La méthode afficher() permet d’afficher le nom du pays, la surface totale du pays, le
nom de la capitale, l’âge moyen des habitants et le nombre d’habitants du pays.
Chapitre 6

Gestion des Exceptions

La gestion des exceptions se substitue en quelque sorte à l’algorithmique permettant


la gestion des erreurs. Chaque programmeur essaye de réduire au minimum le nombre
d’erreurs, mais toutes les erreurs ne peuvent pas forcément ^ etre prévues.
Les erreurs syntaxiques sont toutes interceptées lors de la compilation, mais il reste
souvent des erreurs imprévisibles.
Avec les exceptions, Java propose une approche radicalement différente de l’approche
traditionnelle. En effet, une exception est une sorte de signal qui indique qu’une erreur
ou une situation remarquable est intervenue. Nous dirons qu’une méthode ayant détecté
une situation anormale déclenche une exception. Cette exception sera capturée par le
code.

Nous distinguons deux types d’erreurs : les exceptions et les erreurs :


− Les erreurs sont généralement des erreurs fatales et le programme s’arrête après déclenchement
de ce type des erreurs.
− Les exceptions ne traitent pas forcément des erreurs produites par des erreurs systèmes.
Le concepteur d’une classe peut définir des erreurs (non fatales) pour assurer la robustesse
du code. Par exemple, le débordement d’un tableau est une erreur qui est déclenchée et
qui n’est pas une erreur fatale.

6.1 Définition de l’exception


Une exception est une demande de traitement particulier qui peut arriver à n’importe
quel moment d’un programme. Cette demande se traduit soit par un arrêt du programme,
soit par l’exécution d’une action spéciale qui devra gérer l’exception.
La plupart des exceptions que l’on rencontre sont des exceptions dues à des erreurs (par
exemple division par 0). Quand l’interpréteur rencontre une erreur de ce genre, il déclenche
une exception et arrête le programme.
L’interpréteur exécute alors un programme de gestion d’exceptions. Ce programme ap-
pelé gestionnaire d’exceptions a donc attrapé l’exception déclenchée pour la traiter. Si
aucun gestionnaire d’exceptions n’a été défini, c’est le gestionnaire d’exceptions par défaut
qui sera lancé, affichera l’erreur et arrêtera le programme.
Les exceptions ne sont pas des erreurs, mais plutôt elles permettent de gérer les erreurs.
Elles sont déclenchées par des erreurs.

78
CHAPITRE 6. GESTION DES EXCEPTIONS 79

6.2 La hiérarchie des classes des erreurs et des excep-


tions
En Java, une exception est représentée par une classe. Toutes les exceptions dérivent de
la classe Exception qui dérive de la classe Throwable.

Figure 6.1: Hiérarchie des classes des erreurs et des exceptions

Lorsqu’une méthode, définie dans une classe de la hiérarchie, déclenche une ou plusieurs
exceptions, ceci permet de conserver une trace de la pile d’exécution au moment où la ou
les exceptions sont produites. La machine Java remonte la pile qui contient la suite des
invocations des méthodes jusqu’à atteindre une méthode qui capture cette exception. Si
aucune méthode capturant cette exception n’est trouvée, alors l’exécution s’arrête.

La classe Object est la super-classe de toutes les classes en Java. Elle permet de définir
un comportement global qui peut être exploité par n’importe quelle autre classe.

La classe Throwable contient un attribut remarquable qui contient une “photo” de la


pile d’exécution au moment où l’erreur a été signalée. Cette pile d’exécution (qui mémorise
la file des appels des méthodes), permet de déterminer les circonstances dans lesquelles
l’erreur s’est produite. Si l’application Java “plantait”, cette pile d’exécution serait alors
affichée automatiquement dans la fenêtre d’exécution.

Les objets de la classe Error sont des erreurs relativement graves et une application
(qui n’est pas sensée de la capturer). De même, une application Java n’est pas sensée de
lancer ce type d’erreur.

Une application Java ne travaille généralement qu’avec des objets de la classe Exception.
Dans ce cas, il s’agit d’erreurs qu’une application est susceptible de lancer. Nous pouvons
créer des classes dérivées pour définir des exceptions propres à chaque application.
CHAPITRE 6. GESTION DES EXCEPTIONS 80

6.3 Lever une exception


Pour la classe Personne, définie auparavant, le constructeur devrait produire une ex-
ception si les valeurs fournies en paramètres ne sont pas valides (exemple age d’une per-
sonne doit être strictement positif). Nous allons définir une exception ErrorAge. Pour cela
nous pouvons transmettre le message d’erreur au gestionnaire d’exceptions par l’appel du
constructeur de la classe Exception.

package exemplecours;
public class ErrorAge extends Exception {
public ErrorAge (String message) {
super (message);
}
}

Les raisons pour lesquelles nous préférerons créer une nouvelle classe dérivée de la classe
Exception sont les suivantes :
− Il est parfois utile de disposer d’informations complémentaires sur l’exception. La définition
d’une nouvelle classe permet alors de définir des attributs pour coder ces informations
complémentaires.
− Les exceptions sont filtrées en fonction de leur type pour assurer leur meilleure gestion.
Le choix d’une nouvelle classe permet de filtrer un type bien précis d’exception et non pas
toutes les exceptions de la classe Exception.
− Lorsque, pour chaque type d’exception, nous créons une nouvelle classe, la gestion des
exceptions est bien plus simple. Il n’est pas nécessaire de faire une étude de cas pour
déterminer quel est le type de l’exception.

6.4 Traitement d’une exception


Le traitement des exceptions est effectué dans une partie du programme séparée de
l’endroit du programme où l’erreur a été détectée.
Nous pouvons traiter l’exception par deux possibilités différentes :
− l’exception est traitée directement par la méthode dans laquelle elle s’est produite, nous
disons que l’exception est récupérée ou capturée.
− l’exception est propagée pour être traitée au niveau supérieur. Nous utilisons la propa-
gation de l’exception au cas où la méthode dans laquelle l’exception a été constatée n’est
pas compétente pour faire son traitement.

6.4.1 Capturer une exception


Si le traitement des exceptions se fait localement dans la méthode où les exceptions sont
produites, alors ces exceptions doivent être récupérées par le gestionnaire d’exceptions qui
contient le bloc try-catch.
CHAPITRE 6. GESTION DES EXCEPTIONS 81

Syntaxe :
//...
try {
// Instructions
}
[catch (typeException1 nomException1) {
// Traitement de l’exception n°1
}]
...
[catch (typeExceptionN nomExceptionN) {
// Traitement de l’exception n°N
}]
[finally {
// Traitement relatif au bloc finally
}]

− Le bloc try indique une instruction (ou un bloc d’instructions), susceptible de lever des
exceptions, débute.
− Le bloc catch indique le traitement pour un type particulier d’exceptions.
− Le bloc finally sert à définir un bloc de code à exécuter dans tous les cas (si exception
levée ou non).

Lorsque le programme rencontre une exception dans un bloc try , une exception est
instanciée puis lancée. L’interpréteur cherche un bloc catch à partir de l’endroit ou l’ex-
ception a été créée en cherchant vers le bas. S’il ne trouve aucun bloc catch, l’exception
est lancée dans le bloc de niveau supérieur, ainsi de suite jusqu’au bloc de la classe qui
par défaut enverra l’exception au bloc catch. Celui-ci émettra alors un message d’alerte
standard pour le type d’exception.

a. Le bloc try
Les exceptions levées par une méthode doivent être capturées par la méthode appelante.
Pour ce faire, nous devons encapsuler l’appel de la méthode dans un bloc try.
Les instructions du corps du bloc try sont exécutées jusqu’à la fin de ce bloc si aucune
exception n’est levée. Dans le cas contraire, le contrôle est transféré à l’un des blocs catch.
Un bloc try peut être suivi d’un ou plusieurs blocs catch. Si une exception est déclenchée
dans le code entouré de ces deux blocs, le premier bloc catch qui correspond le mieux au
type de l’exception sera exécutée.
Le gestionnaire d’exceptions peut aussi gérer des exceptions qui se produisent à l’intérieur
des méthodes qui sont appelées par une instruction entourée des blocs try et catch.
CHAPITRE 6. GESTION DES EXCEPTIONS 82

b. Le bloc catch
Le bloc try est suivi par les gestionnaires des exceptions et leurs traitements corres-
pondants dont chacun est annoncé par le bloc catch. Un seul gestionnaire par exception
est autorisé. Lorsqu’une exception est déclenchée dans un bloc try, le bloc catch du ges-
tionnaire d’exceptions (qui accepte un objet exception du type de celle déclenchée) sera
exécutée.
Le nombre de blocs catch est arbitraire et peut être nul. Si aucun bloc catch n’est
prévu pour traiter cette exception, le contrôle est transféré au bloc finally. S’il y a plus
d’un bloc catch, le premier bloc catch (dont le paramètre correspond au type de l’exception
déclenchée) est exécuté. Si l’exception ne correspond à aucun bloc catch, elle remontra à
celui qui a appelé la méthode pour être gérée. Sinon c’est le gestionnaire d’exceptions par
défaut qui s’en occupera en arrêtant le programme. Dans le cas où il n’y a pas eu d’exception
levée par aucune des instructions du bloc try, l’exécution du programme se poursuit après
de dernier bloc catch.
L’ordre des blocs catch est important : si la classe d’un catch dérive de celle d’un autre
catch, alors elle doit être placée devant cette dernière.

c. Le bloc finally
L’intérêt d’un tel bloc repose sur le fait que les instructions qu’il comporte sont toujours
exécutées, qu’une exception soit levée ou pas. Il permet donc de s’assurer par exemple qu’un
fichier ouvert dans le bloc try sera systématiquement refermé, quoi qu’il arrive, grâce au
bloc finally.

Si un bloc finally existe à la fin d’un bloc try, le contrôle est passé alors à cette
portion du code dans tous les cas suivants :
− fin normale du corps du bloc try.
− fin anormale du bloc try.
− sortie du corps du bloc try par un return ou un break.

Le code contenu dans un bloc finally ne peut être ignoré : il n’existe aucun moyen de
quitter un bloc try sans exécuter le bloc finally.
CHAPITRE 6. GESTION DES EXCEPTIONS 83

Exemple :
package exemplecours;
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
Scanner clavier = new Scanner (System.in);
System.out.print ("a = ");
int a=clavier.nextInt();
System.out.print ("b = ");
int b=clavier.nextInt();
try {
System.out.println(a/b);
}
catch(ArithmeticException e) {
System.out.println(e.getMessage());
System.out.println(e.toString());
e.printStackTrace();
}
finally {
System.out.println("fin du programme");
}
}
}

6.4.2 Propagation d’une exception


Propager une exception signifie que le programmeur estime que l’erreur doit être traitée
au niveau supérieur. En effet, lorsqu’une méthode ne contient pas gestionnaires d’exceptions
pour intercepter les exceptions qui peuvent être déclenchées à l’intérieur de cette méthode,
les exceptions non gérées seront renvoyées à la méthode qui a appelé cette méthode pour
les gérer.

a. L’instruction throws
Si une méthode est susceptible de lever une exception qui n’est pas à proximité de la
méthode origine de l’erreur, il faut alors adopter la propagation des exceptions. En
effet, cette méthode doit mentionner le type de l’exception dans son entête en utilisant le
mot-clé throws.
CHAPITRE 6. GESTION DES EXCEPTIONS 84

Syntaxe :
[private/public/protected] type nomMethode ([parametres]) throws
NomException {
// Instructions
}

Cette écriture signifie que la méthode nomMethode est susceptible de générer une ex-
ception de type NomException.

Lorsqu’une méthode lève plusieurs exceptions, elles seront séparées par des virgules dans
l’entête de la méthode.

Syntaxe :
[private/public/protected] type nomMethode ([parametres]) throws
NomException1, ..., NomExceptionN {
// Instructions
}

Les seules exceptions qu’il n’est pas nécessaire de préciser dans le bloc throws sont les
RuntimeException et Error et leurs dérivées.

b. L’instruction throw
Pour lever une exception, il faut utiliser la commande throw qui se traduit par création
d’une instance de la classe où réside cette exception.

Exemple : Nous allons modifier la classe Personne comme suit :

package exemplecours;
public class Personne {
private String nom, prenom;
private int age;
public Personne(String nom, String prenom, int age) throws ErrorAge
{
this.nom = nom;
this.prenom = prenom;
if (age <= 0)
throw new ErrorAge("age doit etre > 0");
else
this.age = age;
}
}
CHAPITRE 6. GESTION DES EXCEPTIONS 85

package exemplecours;
public class ErrorAge extends Exception {
public ErrorAge (string message) {
super (message);
}
}

− L’instruction throws permet de faire remonter l’exception au bloc appelant.


− L’instruction throw déclenche les opérations suivantes :
• A la suite de l’instruction new ErrorAge("age doit etre > 0"), une instance de la
classe ErrorAge est alors créée.
• L’instruction se termine en levant l’exception, c’est-à-dire en signalant l’erreur. Ceci a
pour effet de terminer l’exécution de la méthode et de donner le contrôle au gestionnaire
d’exception.
• Au moyen de la pile d’exécution, le gestionnaire d’exception remonte la file des appels
des méthodes jusqu’à trouver une méthode qui s’est porté candidate pour le traitement de
l’exception.

6.5 Les sources d’exceptions


Deux types de sources d’exceptions existent :
− celles qui sont liées aux applications en utilisant la classe Exception, comme par exemple
des erreurs causées par des références objet qui sont à null.
− celles qui sont causées par le système en utilisant la classe Error, comme par exemple
une application qui demande beaucoup de mémoire.

Si nous examinons les différents types d’exceptions qui peuvent être captées par le
gestionnaire d’exceptions, nous pourrons comprendre les problèmes liés à l’utilisation de
ses classes.
CHAPITRE 6. GESTION DES EXCEPTIONS 86

Classe : RuntimeException
ArithmeticException
Cause :division par zéro, dépassement de capacité d’un entier.
ArrayIndexOutOfBoundsException
Cause :utilisation d’un index du tableau erroné.
ArrayStoreException
Cause : tentative de mettre une valeur dans un tableau de type différent.
ClassCastException
Cause : utilisation du transtypage d’une classe donnée vers une classe dérivée.
IllegalArgumentException
Cause : si nous passons un paramètre qui n’est pas illégal pour une méthode.
IndexOutOfBoundsException
Cause : c’est la classe mère de la classe ArrayIndexOutOfBoundsException
NegativeArraySizeException
Cause : allocation d’un tableau de taille négative.
NullPointerException
Cause : utilisation d’une méthode ou une variable avec une variable qui
contient une référence objet à null.
NumberFormatException
Cause : essai de convertir une cha^ıne non valide en un nombre, ou inversement.
SecurityException
Cause : appel d’une méthode dont le traitement est interdit par les paramètres
de sécurité.
StringIndexOutOfBoundsException
Cause :accès à une position erronée dans une cha^ıne (index négatif ou supérieur
ou égal à la taille de la cha^
ıne).

Classe : Exception
ClassNotFoundException
Cause :générée par le chargeur de classes si un fichier ‘‘.class’’ n’est pas
trouvé au moment d’instanciation d’une classe.
DateFormatException
Cause :les données lues dans une cha^ıne ne sont pas dans un format correct.
IllegalAccessException
Cause : déclenchée par certaines méthodes de ‘‘java.lang.Class’’ lors de
l’instanciation d’une classe à partir de son nom, si la classe n’est pas
publique ou s’il n’y a pas de constructeurs publiques.
InstanciationException
Cause : tentative d’instancier une classe abstraite.
NoSuchMethodException
Cause : une méthode d’un objet ou d’une classe n’est pas trouvée.
RuntimeException
CHAPITRE 6. GESTION DES EXCEPTIONS 87

6.6 Exercices d’application

Exercice 6.1
Tester, corriger et expliquer le programme Java suivant :
Chapitre 7

Utilisation de bases de données avec


JDBC

L’API JDBC (Java data base connectivity) permet de programmer en Java l’accès
aux bases de données locales ou distantes.

Une base de données est constituée d’un ensemble d’informations organisé suivant l’un
des trois modèles suivants : en réseau, hiérarchique ou relationnel. Le dernier, le plus
répandu, consiste à représenter les informations de la base sous la forme d’une ou plu-
sieurs tables.

Une table n’est rien d’autre qu’un tableau a deux dimensions dont les lignes se
nomment des enregistrements et les colonnes des champs.

Un SGBDR (système de gestion de base de données relationnelles) est un logiciel


permettant de créer et d’utiliser de telles bases de données. Il existe de nombreux SGBDR
(nous parlons aussi de moteur de base de données) : Access, MySQL, Oracle, ...

Pour qu’une application Java puisse accéder à une base de données, il suffit que le SGBDR
fournisse un pilote JDBC (ou driver JDBC).

Il s’agit d’un ensemble de classes Java qui vont permettre l’utilisation du SGDB, par le
biais de requêtes SQL. SQL (Structured Query Langage) est un langage d’exploitation de
bases de données très répandu fondé sur des requêtes (nous parlons aussi de demande ou
d’instruction), utilisant une syntaxe simple.

Par exemple, la requête SQL :

SELECT prenom, nom FROM etudiants

88
CHAPITRE 7. UTILISATION DE BASES DE DONNÉES AVEC JDBC 89

Cette requête permettra d’obtenir les valeurs des champs prenom et nom de tous les
enregistrements de la table etudiants.

7.1 Classes de JDBC


Toutes les classes de JDBC sont dans le paquetage java.sql. Il faut donc l’importer
dans tous les programmes devant utiliser JDBC.

import java.sql.*;

Il y a quatre classes et interfaces importantes de JDBC : DriverManager, Connection,


Statement (et PreparedStatement), et ResultSet, chacune correspondant à une étape de
l’accès aux données.

DriverManager :
Charger et configurer le driver de la base de données.
Connection :
Cette interface réalise la connexion et l’authentification à la
base de données.
Statement (et PreparedStatement hérite de l’interface Statement):
Contenir la requ^ete SQL et la transmettre à la base de données.
ResultSet :
Cette interface parcourt les informations retournées par la base
de données dans le cas d’une sélection de données.

7.2 Connexion à la base de données


7.2.1 Prérequis
. Nous devons avoir une base de données MySQL installée.

. Nous devons télécharger le driver JDBC correspondant à MySQL.

. Nous devons créer un projet Java.

7.2.2 Chargement du driver


Java utilise un objet (dit gestionnaire de pilotes), instance de la classe DriverManager,
chargé de gérer les différents pilotes de bases de données existantes. Pour rendre disponible
le “bon pilote”, il existe plusieurs démarches. La plus simple et la plus utilisée consiste à
recourir à la méthode forName de la classe Class en lui fournissant la référence du pilote
concerné.
CHAPITRE 7. UTILISATION DE BASES DE DONNÉES AVEC JDBC 90

/* Chargement du driver JDBC pour MySQL */


try {
Class.forName(‘‘com.mysql.cj.jdbc.Driver’’);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}

− La méthode static forName() de la classe Class peut lever l’exception ClassNotFoundException


si le pilote voulu n’a pas être obtenu.
− Le nom ‘‘com.mysql.cj.jdbc.Driver’’ correspond à un pilote permettant d’accéder
à une base de données MySQL, située sur la même machine que celle sur laquelle s’exécutera
le programme Java.

7.2.3 Identification de l’URL


Pour nous connecter à la base de données MySQL depuis notre application Java, nous
avons besoin d’une URL spécifique à JDBC, qui respecte la syntaxe générale suivante :

jdbc:mysql://nomHote:port/nomDataBase

• nomHote : le nom de l’hôte sur lequel le serveur MySQL est installé. S’il est en place sur
la même machine que l’application Java exécutée, alors vous pouvez simplement spécifier
localhost. Cela peut également être une adresse IP comme 127.0.0.1.
• port : le port TCP/IP écouté par votre serveur MySQL. Par défaut, il s’agit du port
3306.
• nomDataBase : le nom de la base de données à laquelle vous souhaitez vous connecter.

7.2.4 Établissement de la connexion


Pour établir une connexion avec une base de données, nous utilisons la méthode statique
getConnection() de la classe DriverManager.
CHAPITRE 7. UTILISATION DE BASES DE DONNÉES AVEC JDBC 91

/* Connexion à la base de données */


String url = "jdbc:mysql://localhost:3306/etudiants";
String user = "etudiant";
String password = "****";
Connection connec = null;
try {
connec = DriverManager.getConnection(url, user, password);
} catch (SQLException e) {
e.printStackTrace();
}

− La méthode getConnection() peut lever une exception de la classe SQLException.

7.3 Accès à la base de données


7.3.1 Interrogation de la base de données
Une fois la connexion établie, nous pouvons dialoguer avec le SGBDR, par le biais de
requêtes SQL, ce qui permet, notamment :
• d’accéder aux champs des enregistrements d’une table.
• de réaliser des mises à jour d’une table : insertion, suppression ou modification d’enregis-
trements.

Pour transmettre une telle requête au SGBDR, il faut :


• créer un objet dont la classe implémente l’interface Statement, à l’aide de la méthode
createStatement() de la classe Connection.

/* Création de l’objet gérant les requ^


etes */
Statement statement = connec.createStatement();

• appliquer à cet objet statement, la méthode executeQuery() à laquelle nous fournissons


la requête SQL en argument :

statement.executeQuery("SELECT prenom, nom FROM etudiants");

Celle-ci fournit alors en résultat un objet du type ResultSet contenant les informations
sélectionnées.

La méthode executeQuery() est dédiée à la lecture de données via une requête de type
SELECT. Tandis que, la méthode executeUpdate()est réservée à l’exécution de requêtes
ayant un effet sur la base de données (écriture ou suppression), typiquement les requêtes
du type INSERT, UPDATE, DELETE, etc.
CHAPITRE 7. UTILISATION DE BASES DE DONNÉES AVEC JDBC 92

7.3.2 Exploitation du résultat


L’objet, du type ResultSet fourni par executeQuery(), dispose de méthodes permet-
tant de le parcourir enregistrement par enregistrement à l’aide d’un “curseur”.
• la méthode next() fait progresser le curseur d’un enregistrement au suivant, en fournis-
sant la valeur null s’il n’y a plus d’enregistrement.
• au départ le curseur est positionné avant le premier enregistrement ; il faut donc effectuer
un appel à next() pour qu’il soit bien positionné sur le premier enregistrement (s’il existe)
de l’objet résultat.

ResultSet result;
result = statement.executeQuery("SELECT prenom, nom FROM etudiant");
String prenom, nom;
while(result.next()){
prenom = result.getString(1);
nom = result.getString(2);
System.out.println(prenom + " " + nom);
}

7.4 Libération des ressources


En théorie, l’objet représentant la connexion sera automatiquement détruit par le ramasse-
miettes dès qu’il ne sera plus utilisé. Cependant, cette destruction n’avoir lieu qu’après la
fin du programme. Dans des applications réelles, où plusieurs utilisateurs peuvent accéder
à une même base de données, il sera préférable de détruire cet objet dès que possible :

connec.close();

− Notez que l’objet résultat (du type ResultSet) n’est plus accessible lorsque la connexion
est fermée.
− Les objets du type Statement et ResultSet disposent également de méthode close().
CHAPITRE 7. UTILISATION DE BASES DE DONNÉES AVEC JDBC 93

7.5 Exercices d’application

Exercice 8.1
Soit le programme Java suivant :

Ajouter les instructions nécessaires pour créer la table “etudiant” et insérer/supprimer


des enregistrements.

Exercice 8.2
Refaire l’exercice “Exercice 3.2 ” en utilisant des tables pour stocker les informations (les
comptes, ...) des clients.

Une fonction de hachage (MD5, SHA-1, SHA 256) cryptographique est une primitive
cryptographique qui transforme un message de taille arbitraire en un message de taille
fixe, appelé un condensé. Les fonctions de hachage cryptographiques sont employées pour
l’authentification, les signatures numériques et les codes d’authentification de messages.
Pour être utilisable en cryptographie, une fonction de hachage doit disposer de ces qualités :
• rapide à calculer (parce qu’elles sont fréquemment sollicitées).
• non réversible (chaque condensé peut provenir d’un très grand nombre de messages,
et seule la force brute peut générer un message qui conduit à un condensé donné).
CHAPITRE 7. UTILISATION DE BASES DE DONNÉES AVEC JDBC 94

• résistant à la falsification (la moindre modification du message aboutit à un condensé


différent)
• résistant aux collisions (il devrait être impossible de trouver deux messages différents
qui produisent le même condensé)
Chapitre 8

Les collections

La collection en Java est un framework (cadre) qui fournit une architecture pour stocker
et manipuler un groupe d’objets.
Les collections Java peuvent réaliser toutes les opérations que vous effectuez sur des
données telles que la recherche, le tri, l’insertion, la manipulation et la suppression.
Le framework Java Collection fournit de nombreuses interfaces (Set, List, Queue, Deque)
et classes (ArrayList, Vector, LinkedList, PriorityQueue, HashSet, LinkedHashSet, Tree-
Set).

8.1 Hiérarchie de Collection Framework


Le paquetage ‘‘java.util’’ contient toutes les classes et interfaces du framework
Collection.

Figure 8.1: Hiérarchie de Collection Framework


95
CHAPITRE 8. LES COLLECTIONS 96

8.1.1 Interface Iterable


L’interface Iterable est l’interface racine pour toutes les classes de collection.
Il ne contient qu’une seule méthode abstraite.

Iterator<T> iterator()

Elle retourne l’itérateur sur les éléments de type T.

8.1.2 Interface Collection


L’interface Collection est l’interface qui est implémentée par toutes les classes du fra-
mework Collection. En d’autres termes, l’interface Collection constitue la base sur laquelle
repose le framework Collection.

Certaines des méthodes de l’interface Collection sont : Boolean add (Object obj),
Boolean addAll (Collection c), void clear(), etc ; qui sont implémentées par toutes
les sous-classes de l’interface Collection.

8.2 Interface List


L’interface List est l’interface fille de l’interface Collection. Cette interface est implémentée
par les classes ArrayList, LinkedList, Vector et Stack.

Pour instancier l’interface List, nous devons utiliser :

List <type de données> list1= new ArrayList<type de données>();


List <type de données> list2 = new LinkedList<type de
données>();
List <type de données> list3 = new Vector<type de données>();
List <type de données> list4 = new Stack<type de données>();

Il existe plusieurs méthodes de l’interface List qui peuvent être utilisées pour insérer,
supprimer et accéder aux éléments de la liste.

8.2.1 La classe ArrayList


La classe ArrayList implémente l’interface List. Elle utilise un tableau dynamique
pour stocker les éléments dupliqués de différents types de données. La classe ArrayList
conserve l’ordre d’insertion et n’est pas synchronisée.
CHAPITRE 8. LES COLLECTIONS 97

Exemple :

import java.util.*;
public class TestArrayList {
public static void main(String[] args) {
// Création ArrayList
ArrayList<String> etudiant=new ArrayList<String>();
// Ajout d’un objet dans ArrayList
etudiant.add("Issam Seddik");
etudiant.add("Mohamed Chillou");
etudiant.add("Mohamed Fournan");
etudiant.add("Hassan Talhaoui");
etudiant.add("Samia Dadou");
etudiant.add("Rania El-Otmani");
etudiant.add("Siham Baallal");
etudiant.add("Omayma Nabil");
etudiant.add("Jouhayna Driouach");
etudiant.add("Manal Afkir");
etudiant.add("Saliha Abokar");
etudiant.add("Khadija Ousfya");
etudiant.add("Ikram Idrissi");
etudiant.add("Zayneb El Bercani");
etudiant.add("Hanae Aurag");
etudiant.add("Redouan Bayyay");
etudiant.add("Xxxxxx Yyyyyyyy");
for (int i=0; i<etudiant.size(); i++) {
System.out.println(etudiant.get(i));
}
etudiant.set(16, "anonymous anonymous");
// Parcours la liste via Iterator
Iterator itr=etudiant.iterator();
while(itr.hasNext()){
System.out.println(itr.next());
}
etudiant.remove(16);
for (String e: etudiant) {
System.out.println(e);
}
System.out.println(etudiant) ;
}}

− Méthode add() utilisée pour ajouter des éléments à l’ArrayList.


CHAPITRE 8. LES COLLECTIONS 98

− Méthode get() utilisée pour accéder à un élément de l’ArrayList.

− Méthode set() utilisée pour modifier un élément de la liste.

− Méthode remove() utilisée pour supprimer un élément.

− Méthode size() utilisée pour connaı̂tre le nombre d’éléments de la liste.

− hasNext() retourne vrai si l’iterator a plus d’éléments sinon il retourne faux.

− next() retourne l’élément et déplace le pointeur du curseur vers l’élément suivant.

8.3 Interface Set


L’interface Set en Java est présente dans le paquetage ‘‘java.util’’. Elle hérite de
l’interface Collection. Elle représente l’ensemble non ordonné d’éléments qui ne nous per-
met pas de stocker les éléments dupliqués. Set est implémentée par les classes : HashSet,
LinkedHashSet, et TreeSet.

Set peut être instanciée comme :

Set <type de données> s1= new HashSet<type de données>();


Set <type de données> s2 = new LinkedHashSet<type de données>();
Set <type de données> s3 = new TreeSet<type de données>();

8.3.1 HashSet
La classe HashSet implémente l’interface Set. Elle représente la collection qui utilise une
table de hachage pour le stockage. Le hachage est utilisé pour stocker les éléments dans le
HashSet. Il contient des éléments uniques.

Exemple :
CHAPITRE 8. LES COLLECTIONS 99

import java.util.*;
public class TestHashSet {
public static void main(String[] args) {
// Création HashSet
Set<String> etudiant=new HashSet<String>();
// Ajout d’un objet dans HashSet
etudiant.add("Jamal Boussouf");
etudiant.add("Mohamed El Abdallaoui");
etudiant.add("Widad Boukadida");
etudiant.add("Zakaria Chamlal");
etudiant.add("Lamyae Azouagh");
etudiant.add("Chaymae Yahyati");
etudiant.add("Jamal Boussouf");
etudiant.add("Xxxx Xxxxxxxx");
// Parcours la liste via Iterator
Iterator itr=etudiant.iterator();
while(itr.hasNext()){
System.out.println(itr.next());
}
etudiant.remove("Xxxx Xxxxxxxx");
for (String e: etudiant) {
System.out.println(e);
}
}}

Pour plus de détails sur les collections Java, reportez-vous à :

https ://www.javatpoint.com/collections-in-java
Chapitre 9

Paquetages et quelques classes en


Java

9.1 Les paquetages


Un paquetage est un regroupement de classes et d’interfaces apportant de fonction-
nalités complémentaires. Il est proche de la notion de bibliothèque que l’on trouve dans
d’autres langages.

Exemple : Le paquetage java.io regroupe tout ce qui concerne les entrées/sorties.

Le mot-clé package spécifie de quel paquetage le code fait partie. Le code Java qui
fait partie d’un paquetage particulier a accès à toutes les classes qui font partie du même
paquetage.
La déclaration d’un paquetage se fait au début d’un fichier source comme suit :

Syntaxe :
package nompaquetage;

En cas d’absence de cette instruction de déclaration d’un paquetage dans un fichier


source, le compilateur considère que les classes de ce fichier appartiennent au paquetage
par défaut c-à-d le paquetage courant.
Il est préférable qu’un nom de paquetage soit écrit entièrement en minuscule.

9.1.1 Attribution d’une classe à un paquetage


L’attribution d’un nom de paquetage se fait au niveau du fichier source indiquant pour
chaque fichier de quel paquetage il fait partie.
Si un programme fait référence à une classe, le compilateur cherche la classe référencée
dans le paquetage par défaut.
Pour utiliser une classe appartenant à un paquetage, autre que celui par défaut, il est
nécessaire de fournir l’information correspondant au compilateur. Nous pourrons le faire
par l’un des trois cas suivants :

a. Référence d’une classe par rapport à son paquetage


Nous pouvons référencer une classe en la préfixant par le nom de son paquetage.
100
CHAPITRE 9. PAQUETAGES ET QUELQUES CLASSES EN JAVA 101

Syntaxe :
nompaquetage.NomClasse

Exemple :
package packagetest;
public class Test {
public static void main (String args[]){
//...
exemplecours.Personne p = new exemplecours.Personne();
p.afficher();
}
}

Cette démarche devient fastidieuse dès que nombreuses classes sont appelées.

b. Importation d’une classe


L’instruction import permet d’importer une ou plusieurs classes pour les rendre acces-
sibles.

Syntaxe :
import nompaquetage.NomClasse;

Exemple :
package packagetest;
import exemplecours.Personne;
public class Test {
public static void main (String args[]){
//...
Personne p = new Personne();
p.afficher();
}
}

c. Importation d’un paquetage


L’instruction import peut importer tout un paquetage. Nous pourrons ensuite utiliser
toutes les classes du paquetage importé sans les préfixer par le nom de leur paquetage.
CHAPITRE 9. PAQUETAGES ET QUELQUES CLASSES EN JAVA 102

Syntaxe :
import nompaquetage.*;

Si nous disposons de plusieurs classes ayant le même nom et appartenant à des paque-
tages différents, le nom du paquetage doit préfixer le nom de la classe pour distinguer entre
ces classes.

9.1.2 Les paquetages standard


Les classes standard, avec lesquelles Java est fourni, sont structurées en paquetages. Il
existe en particulier un paquetage nommé java.lang qui est automatiquement importé
par le compilateur. Il permet d’utiliser directement les classes standard telles que Math,
System, Float, Integer, ...

9.2 Quelques classes d’usage fréquent


9.2.1 La classe Scanner
Pour que Java puisse lire ce qui est tapé au clavier, il va falloir utiliser un objet de type
Scanner qu’il faudra instancier. Pour faire ceci, il faut importer la classe Scanner qui se
trouve dans le paquetage ‘‘java.util’’.

Syntaxe:
import java.util.Scanner;
// ...
Scanner sc = new Scanner(System.in);

Pour récupérer les données, il faut faire appel sur l’objet sc aux méthodes prédéfinies
suivantes :

• String next(): donnée de la classe String qui forme un mot.


• String nextLine(): donnée de la classe String qui forme une ligne.
• boolean nextBoolean(): donnée booléenne.
• int nextInt(): donnée entière de type int.
• float nextFloat(): donnée réelle de type float.
• double nextDouble(): donnée réelle de type double.
• ...
CHAPITRE 9. PAQUETAGES ET QUELQUES CLASSES EN JAVA 103

package exemplecours;
import java.util.Scanner;
public class TestScanner {
public static void main (String args []){
Scanner sc = new Scanner (System.in);
String nom, prenom;
int age;
System.out.println("Saisir votre nom : ");
nom = sc.nextLine();
System.out.println("Saisir votre prénom : ");
prenom = sc.nextLine();
System.out.println("Saisir votre age : ");
age = sc.nextInt();
//...
}
}

9.2.2 La classe Math


Java supporte directement les opérations sur les nombres entiers et flottants. Les opérations
mathématiques sont gérées via la classe java.lang.Math. Cette classe est utilisée comme
une bibliothèque mathématique qui n’a pas de constructeurs, donc elle ne peut pas être
instanciée. Pour cela, lorsqu’on utilise ses méthodes, il faut les préfixer avec le nom de la
classe.

Exemple :
double x, y=9;
x=Math.sqrt(y);

Quelques méthodes

double sqrt(double x) //retourne la racine carrée.


double cos(double x), double sin(double x), double tan (double x)
double pow(double x, double y) //xy
double ceil(double x) //retourne le plus petit nombre entier
supérieur ou égal à x.
double floor(double x) //retourne le plus grand nombre entier
inférieur ou égal à x.
double max(double x, double y) //retourne le maximum entre x et y.
double min(double x, double y) //retourne le minimum entre x et y.
CHAPITRE 9. PAQUETAGES ET QUELQUES CLASSES EN JAVA 104

9.2.3 La classe Date


La manipulation de cette classe nécessite l’importation du paquetage “java.util.Date”.

Quelques méthodes

//Constructeurs de la classe Date qui initialisent un objet avec des


paramètres.
Date()
Date(int year, int month, int date)
Date(int year, int month, int date, int hrs, int min)
Date(int year, int month, int date, int hrs, int min, int sec)
...
Exemple: Date d=new Date();
//Retourne l’information demandée à partir de la date courante.
int getDate()
int getDay()
int getHours()
int getMinutes()
int getMonth()
int getSeconds()
int getYear()
Exemple: int year=d.getYear();
//Modifie l’information spécifiée à partir de la date courante.
void setDate(int date)
void setHours(int hours)
void setMinutes(int minutes)
void setMonth(int month)
void setSeconds(int seconds)
void setYear(int year)
Exemple: d.setYear(2019);
//Retourne un objet String représentant la valeur de l’objet Date.
String toString()
Exemple: System.out.println(d.toString());

N.B. La portion de code suivante :

Etudiant e = new Etudiant ("Azzouz", "Anissa", "SMI");


System.out.println(e);

Afficherait la valeur de la référence. Par exemple : exercice.Etudiant@2a139a57.


CHAPITRE 9. PAQUETAGES ET QUELQUES CLASSES EN JAVA 105

Pour afficher le contenu de l’objet en utilisant exactement le même code, Java fournit
une méthode, appelée toString(), qui retourne une représentation de l’instance sous forme
d’une String.
La méthode toString() est invoquée automatiquement par System.out.println.

package exemplecours;
public class Etudiant {
private String nom, prenom, filiere;
public Etudiant (String nom, String prenom, String filiere){
this.nom=nom;
this.prenom=prenom;
this.filiere=filiere;
}
public String toString (){
return ‘‘nom :’’+nom+‘‘prénom :’’+prenom+‘‘filière:’’+filiere;
}
}

package exemplecours;
public class Test {
public static void main (String args []){
Etudiant e = new Etudiant ("Azzouz", "Anissa", "SMI");
System.out.println(e);
}
}
Mini-projets

Mini-projet 1. Envoi et réception d’e-mails sécurisés en Java.

Mini-projet 2. Création d’une Blockchain (gestion des transactions) en Java.

Les étudiants (en binôme) doivent :


• réaliser un de ces mini-projets.
• réaliser la conception UML (diagrammes use case, séquence et classe).
• préparer un mini-rapport.

106

Vous aimerez peut-être aussi