coursPOO 2020
coursPOO 2020
coursPOO 2020
FICHE PEDAGOGIQUE
OBJECTIFS
Comprendre les concepts de la programmation orientée objet
Implémenter des classes d’objets
Créer des classes avec le principe d’héritage
PRE-REQUIS
Algorithmique
Atelier Programmation 1
Atelier Programmation 2
POPULATION
Profil : Technologie de l’informatique
Spécialité : Tronc commun
Niveau : Semestre 3
DEROULEMENT
Durée : 15 semaines
Volume horaire : 3 heures Cours/semaine
EVALUATION
Interrogation orale
Un devoir d’une heure
Examen final écrit de 2 heures
MOYENS PEDAGOGIQUES
Exposé informel
Tableau
Support du cours
Exercices d’application
Chapitre I
Vue d’ensemble
Le but de cette première leçon est d’introduire la programmation orientée objet et les langages
orientées objets
Objectifs
Sensibiliser l’étudiant aux avantages de la programmation orientée objet.
Se familiariser avec les termes de la programmation orientée objet
Découvrir les principaux concepts de la programmation orientée objet
Durée : 1 h 30mn
Pré-requis :
Algorithmique et structures de données 1
Atelier de programmation 1
Premiers langages : suite d’instructions qui s’exécutent de façon linéaire (l’une après
l’autre)
Aucune modularité
Pas de possibilité de réutilisation
La modélisation objet crée une représentation informatique des éléments du monde réel
indépendamment de l’implémentation.
Extensibilité / évolutivité
Fiabilité : conservation de l’intégrité des données
Les données et les fonctions sont éclatées (vision décentralisée et
nontemporelle)
Réutilisation
Abstraction : analyse du problème indépendamment du codage
Un objet représente une entité du monde réel. Il est caractérisé par un état et un
comportement.
L’état d’un objet est l’ensemble des données qui le décrivent qu’on appelle attributs. Le
comportement décrit les traitements associés à l’objet qu’on appelle méthodes.
Un objet regroupe les données et les moyens de traitement de ces données (fonctions
membres / méthodes)
Exemples :
Objet 1 : Peugeot 206 Objet 2 : Ford Fiesta
2.2. Classe
Une classe d’objets est une description d’un ensemble d’objets ayant un état commun et
disposant des mêmes comportements.
Une classe représente un type abstrait de données à partir duquel il est possible de créer
différents objets.
2.3. Instanciation
Une classe représente un modèle d’objet à partir duquel on peut avoir plusieurs exemplaires
(objets). Ces objets sont appelés des instances de classe. La création d’une classe s’appelle
instanciation.
Lors de la déclaration d’une instance de classe, c’est à dire lorsqu’un objet est créé, une
méthode (fonction membre) est appelée automatiquement. Cette méthode s’appelle
constructeur et a pour rôle d’initialiser l’objet de la classe en question.
Inversement, une méthode appelée destructeur est appelée automatiquement lorsque
l’instance est hors de portée (fin du programme).
2.5. Encapsulation
Mécanisme qui permet de conserver l’intégrité des données en empêchant l’accès aux
attributs par un moyen autre que les méthodes proposées : c’est le masquage de certains
éléments de la classe.
On peut distinguer dans une classe, principalement, 2 parties :
Partie publique : Accessible par tous les composants du programme ; c’est
l’interface de la classe,
Partie privée : Accessible uniquement par les méthodes de la classe.
2.6. Héritage
L’héritage permet de définir les bases d’une nouvelle classe objet à partir d’une classe
existante.
Les classes obtenues par l’héritage sont appelées des classes dérivées ou classes filles, les
classes d’origine sont des classes mères ou classes de base.
2.7. Polymorphisme
Le nom de polymorphisme vient du grec et signifie qui peut prendre plusieurs formes.
Une même opération peut se comporter différemment pour différentes classes/ objets.
Chapitre II
Vue d’ensemble
Le but de cette deuxième leçon est d’introduire la syntaxe et les éléments de base en java
Objectifs
A la fin de cette leçon, l’étudient sera capable :
De connaitre la structure d’un programme java
De déclarer des variables en java en utilisant les types primitifs et prédéfinies
D’utiliser les structures conditionnelles et répétitives du langage java
Durée : 4.5 h
Pré-requis :
Algorithmique et structures de données 1
Atelier de programmation 1
1. Introduction
Un programme Java est une collection d’un ou de plusieurs fichiers source. Au moins
l’un de ces fichiers contient une classe publique unique avec une méthode unique dont
la signature est la suivante :
public static void main(String[] args)
Chaque fichier du programme doit comprendre une classe ou bien une interface
publique et est appelé X.java, X correspond au nom de la classe ou de l’interface
publique. Chaque fichier X.java est compilé dans un fichier classe appelé X.class. Le
programme est ensuite lancé en exécutant le fichier X.class qui contient la méthode
main comprenant les instructions à exécuter.
Cette programmation peut être effectuée à partir de la ligne de commande ou bien d’un
environnement de développement intégré IDE.
Toutes les instructions Java doivent apparaître au sein des méthodes et toutes les méthodes
doivent apparaître au sein d’une définition de classe.
Le programme ci avant déclare une classe appelée MaClasse et une signature d’une
unique méthode appelée main. Les membres de la classe apparaissent entre des accolades {
}, après le nom de la classe.
La méthode main est capable par exemple de créer des objets, évaluer des expressions,
invoquer des méthodes. Elle débute l’exécution de l’application Java.
La méthode main est déclarée :
o public pour qu’elle soit appelable depuis n’importe où (ici depuis la JVM).
o static pour indiquer que la méthode appartient directement à la classe et elle n’est
pas associée à une instance.
o Le type de retour de la méthode main est void pour indiquer qu’elle ne retourne rien
et elle n’a pas de type de retour.
Le seul paramètre de la méthode main est un tableau d’objets String (chaînes) référencée
avec l’attribut args.
Le corps de la méthode est constitué par un bloc d’instructions compris entre une paire
d’accolades { }. Chaque instruction se termine par un point virgule. Dans cet exemple, le
corps de la méthode main contient une seule instruction.
Une méthode est invoquée en utilisant la référence d’un objet (System.out :
correspondant au champ out de la classe System) et un nom de méthode println séparée par
un point. La chaîne de caractères « Bonjour à tous » est passée en argument à la méthode
println.
Les lignes 8 et 9 contiennent des commentaires. Un commentaire qui débute par // est
appelé commentaire en une seule ligne. Un commentaire qui s’étend sur plusieurs lignes
(commentaire multi lignes) est délimité par un /* et se termine par */ . Java a introduit de
plus le commentaire de documentation, délimité par /** et */ .
3. Les identificateurs
Pour désigner un élément d’un programme (variable, objet, méthode, classe, …), on utilise
des identificateurs. Il existe des règles permettant de choisir un identificateur.
Les identificateurs en Java peuvent commencer par une lettre, par le caractère de
soulignement _ ou par le signe dollar $. Le reste du nom peut comporter des lettres ou des
nombres mais jamais d'espaces. Un identificateur doit être différent des mots réservés du
langage Java (public, break, private, final, abstract, …).
4. Les variables
Dans le cadre de tous les langages de programmation, l’accès aux données est effectué via
des variables. Avec Java une variable est soit une référence à un objet, soit un type primitif.
S’il s’agit d’une référence, sa valeur est null ou bien elle contient l’adresse d’un objet
instancié.
Types Java
Types primitifs
booléen
Types numériques
Types entiers
byte
short
int
long
char
Types à virgule flottante
float
double
Types de références
type tableau
type classe
type Interface
Figure 1 : Types des variables JAVA
Le langage Java contient huit types prédéfinis ou primitifs pour fournir un support aux entiers,
flottants, booléens et caractère. Les types primitifs de Java sont :
-2147483648 à
Int entier signé 32 bits
2147483647
virgule flottante
1.401e-045 à
Float simple précision 32 bits
3.40282e+038
(IEEE754)
virgule flottante
2.22507e-308 à
Double double précision 64 bits
1.79769e+308
(IEEE754)
-
9223372036854775808
Long entier long 64 bits
à
9223372036854775807
Remarque :
Java autorise la conversion des valeurs entières et des valeurs en virgule flottante. Le type
char peut être aussi convertit en type entier et en virgule flottante. Il est possible de forcer la
conversion de type au moyen de transtypage, en plaçant le nom de type souhaité entre
parenthèses devant la valeur à convertir.
Exemple :
float p = 3,14 ;
int x = (int) p ;
Java est sensible à la casse.
Les types élémentaires commencent tous par une minuscule.
Tous les types primitifs en java possèdent des classes correspondantes à l’exception de
type booléen.
Pour manipuler les chaînes de caractères, Java offre une classe appelée String et une
constante chaîne de caractères.
Java permet de manipuler une référence à un objet donné au lieu de manipuler directement
un objet tableau ou un objet de classe.
Une variable possède un nom, un type et une valeur. La déclaration d'une variable est faite en
spécifiant son nom et son type de données.
<type> nom_de_la_variable
Une variable est utilisable dans le bloc où elle est définie. La déclaration d'une variable permet
de réserver la mémoire pour en stocker la valeur.
Exemple :
int compteur; // déclaration d’une variable compteur de type entier
int a = 5 ; // déclaration d’une variable a de type entier et initialisée à 5
String chaine; // déclaration d’une variable chaine de type String
int jour, mois, annee ; // déclaration des variables de même type séparés par une
virgule
Pour les objets, il est nécessaire en plus de la déclaration de la variable de créer un objet avant
de pouvoir l'utiliser. Il faut réserver de la mémoire pour la création d'un objet (un tableau est un
objet en Java) avec l'instruction new.
Une variable de référence ne peut contenir qu’une seule valeur. Si cette référence n’est pas
nulle, elle pointe vers l’objet auquel elle fait référence. En Java, un objet ne peut pas exister si
une variable de référence ne pointe pas vers lui.
String pt = null; création d’une variable de référence nulle qui ne pointe pas vers un objet.
pt
String
String pays = new String ("France"); création d’un objet nommé pays et de type String.
Techniquement pays est le nom de la variable faisant référence à l’objet String.
pays "France"
Exemple :
String
= a=10 équivalent à : a = 10
+= a+=10 équivalent à : a = a + 10
-= a-= équivalent à : a = a - 10
*= a*= équivalent à : a = a * 10
/= a/=10 équivalent à : a = a / 10
^= a^=10 équivalent à : a = a ^ 10
<<= a<<=10 équivalent à : a = a << 10 a est complété par des zéros à droite
>>= a>>=10 équivalent à : a = a >> 10 a est complété par des zéros à gauche
Remarque :
Lors d'une opération sur des opérandes de types différents, le compilateur détermine le type du
résultat en prenant le type le plus précis des opérandes. Par exemple, une multiplication d'une
variable de type float avec une variable de type double donne un résultat de type double. Lors
d'une opération entre un opérande entier et un flottant, le résultat est du type de l'opérande
flottant.
Comme la plupart des langages de développement orienté objets, Java propose un ensemble
d'instructions qui permettent d'organiser et de structurer les traitements.
Instructions Désignation
While ( boolean )
Le code est exécuté tant que le booléen est vrai. Si
{
avant l'instruction while, le booléen est faux, alors le
// code a exécuter dans la boucle
code de la boucle ne sera jamais exécuté.
}
do {
Cette boucle est au moins exécuté une fois quelque soit
...
la valeur du booléen.
} while ( boolean )
for (initialisation; condition; modification)
Dans l'initialisation, on peut déclarer une variable qui
{
servira d'index et qui sera dans ce cas locale à la
...
boucle.
}
if (Boolean) {
...// code 1 à exécuter
} else if (boolean) { Le code est exécuté tant que le booléen est vrai, sinon
...// code 2 à exécuter si le booléen est vrai le code 2 est exécuté sinon le
} else { dernier code est exécuté.
...// code
}
switch (expression) {
case constante1 :
instr11;
On ne peut utiliser switch qu'avec des types primitifs
instr12;
d'une taille maximum de 32 bits (byte, short, int, char).
break;
case constante2 :
Si une instruction case ne contient pas de break alors
...
les traitements associés au case suivant sont exécutés.
default :
...
}
break
permet de quitter immédiatement une boucle ou un
branchement. Utilisable dans tous les contrôles de flot.
continue
s'utilise dans une boucle pour passer directement à
l'itération suivante.
6. Les tableaux
Un tableau est une collection de variables qui portent tous le même nom et le même type.
Ces valeurs peuvent être des valeurs primitives ou des objets ou encore d’autres tableaux.
Pour faire référence à un emplacement donné, c'est-à-dire à un élément du tableau, nous
spécifions le nom du tableau et le numéro de position de cet élément particulier du tableau.
Dans le cadre du langage de programmation Java, les tableaux présentent les propriétés
suivantes :
Un programme peut déclarer des tableaux de tout type de donnée. Chaque élément d’un
tableau qui contient un type de donnée primitif correspond à une valeur de ce type. Par
exemple, chaque élément d’un tableau de type int contient une valeur int. A l’opposé, si le
tableau contient des objets, chaque élément correspond à une référence vers ce type d’objet.
Ainsi, chaque élément d’un tableau de type String équivaut à une référence de type String
qui possède la valeur null par défaut.
Java permet de placer les crochets après ou avant le nom du tableau dans la déclaration.
Les tableaux sont des objets qui occupent de la place en mémoire. Tous les objets de Java,
les tableaux compris, doivent recevoir une allocation dynamique de mémoire avec
l’opérateur new. Il faut spécifier la taille d’un tableau.
Une même déclaration peut réserver de la mémoire pour plusieurs tableaux de même type.
Par exemple, on déclare un tableau b de type String et 27 éléments pour le tableau x de
String :
L’accès à un élément du tableau se fait au moyen d’un indice entier. Les indices du tableau
commencent à partir de 0.
Un objet tableau possède un champ lenght indiquant le nombre d’éléments contenus dans
un tableau. Les bornes de tableau commence de 0 et se termine par lenght – 1. Dans le cas
où l’index dépasse les bornes du tableau, une exception
ArrayIndexOutOfBoundsException est lancée. Les exceptions seront présentées un plus
tard. Un tableau de taille nulle est un tableau vide.
Java initialise chaque élément d’un tableau à 0 s’il correspond à un type de donnée primitif,
à false s’il représente une variable de type boolean ou à null s’il s’agit d’une référence
(c'est-à-dire de tout type non primitif).
La taille du tableau n'est pas obligatoire si le tableau est initialisé à sa création. Le nombre
d’éléments de la liste d’initialisation détermine la taille de tableau. Par exemple, la
déclaration
int tableau[5] = {10,20,30,40,50};
crée un tableau de cinq éléments avec les indices 0, 1, 2, 3 et 4. Lorsque le compilateur
rencontre une liste d’éléments d’initialisation, il compte le nombre d’éléments
d’initialisation et génère automatiquement l’opérateur new qui permet de créer l’objet
tableau correspondant.
Le langage Java ne prend pas directement en charge les tableaux à indices multiples. Cependant,
il permet la définition d’un tableau à un indice dont les éléments sont à leur tour des tableaux à
un indice. Dans la déclaration de ce type de tableau, toute paire de crochet représente une
dimension.
L’accès à un élément du tableau nécessite de spécifier autant de valeurs d’indices que de
dimensions. Lors de la création du tableau avec l’opérateur new, il est indispensable de spécifier
toutes les dimensions. Cependant, il est possible de ne pas spécifier toutes les dimensions mais
il faut surtout spécifier les dimensions les plus à gauche.
int [] [] tab = new int [10] [10] ; // création d’un tableau de 2 dimensions
int [] [] tab = new int [ ] [10] ; // la dimension n’est pas spécifiée à gauche (c’est faux)
Exemple :
Les tableaux à deux indices représentent des tables de valeurs, disposées en rangées et colonnes.
Pour identifier un élément bien déterminé d’une table, il faut en indiquer les deux indices : le
premier désigne la rangée de l’élément dans la table et le second désigne la colonne. Soit la
déclaration suivante : int b [] [] = {{1, 2},{3, 4}} ;
Colonne 0 Colonne 1
Rangée 0 b[ 0 ] [ 0 ] b[ 0 ] [ 1 ] Colonne 0 Colonne 1
Rangée 1 b[ 1 ] [ 0 ] b[ 1 ] [ 1 ]. Rangée 0 1 2
Rangée 1 3 4
Nom du tableau
Il faut spécifier le nom du tableau sans les crochets droits pour le passer en argument à une
méthode. Par exemple, si nous déclarons le tableau tableau1 comme suit :
modifierTableau ( tableau1) ;
passe le tableau tableau1 à la méthode modifierTableau. En Java, chaque objet tableau connaît
sa propre taille via la variable lenght. Par conséquent, lorsqu’on passe un objet tableau à une
méthode, il n’est pas nécessaire de signifier au passage la taille du tableau.
Le nom du tableau suivi de l’indice d’un élément indiqué en argument d’une méthode permet
le passage de l’élément à la méthode. Soit par exemple :
modifierElement ( tableau1 [ 3 ]) ;
Pour qu’une méthode puisse recevoir un tableau par le biais d’un appel de méthode, la liste de
paramètres de la méthode doit spécifier un paramètre de tableau (ou plusieurs si nécessaire).
Par exemple, l’en-tête de la méthode modifierTableau qui correspond à
Exercice 1 :
Qu’affiche ce programme ?
Exercice 2 :
Ecrivez des instructions Java différentes qui accomplissent chacune les tâches suivantes :
1. Entrer chaque résultat du test (1 ou 2). Afficher le message « entrer résultat » à l’écran
chaque fois que le programme réclame un autre résultat.
2. Compter le nombre de résultats du test de chaque type.
3. Afficher un résumé des résultats du test indiquant le nombre d’étudiants qui ont réussi
et le nombre d’étudiants qui ont échoué.
4. Si plus de 8 étudiants ont réussi l’examen, afficher le message « Promouvoir le
cours ».
Chapitre III
Vue d’ensemble
Pré-requis :
Algorithmique et structures de données 1
Atelier de programmation 1
Syntaxe et éléments de base en java
1. Introduction
Comme le langage Java est "Orienté Objet", il est entièrement basé sur la notion
d'encapsulation, c'est-à-dire qu’il permet de définir des classes qui contiennent des
membres. Les membres sont soit des champs soit des méthodes. L'instance de la classe
(appelé objet) est alors implicitement passée en paramètre à la méthode.
Les champs (parfois appelé attribut) sont des variables qui définissent des caractéristiques
propres à chaque objet (variables d’instance) ou à un groupe d’objets de la classe (variables
de classe). Ces variables ont une portée différente suivant l’endroit où elles sont déclarées.
Les méthodes sont des fonctions qui définissent les comportements des objets de la classe.
Contrairement au C/C++, Java est « purement » orienté objet, c’est-à-dire qu’il est
impossible de définir des fonctions autres que des méthodes.
2. Classes et objets
Pour qu'un objet puisse réellement exister au sein de la machine, il faut qu'il puisse stocker
son état dans une zone de la mémoire. La seule manière de créer un objet d’une classe en
Java est d’utiliser l’opérateur new. Cet opérateur doit être suivi du nom de la classe dans
lequel l’objet est crée. L’opérateur new détermine la place mémoire nécessaire à la
définition d’un objet. La création d'un objet est parfois appelée instanciation.
Voici quelques exemples d’instanciation d’objets :
String chaine = new String ();
Point2D point = new Point2D ();
String chaine2 = new String ("Bonjour");
Les opérations réalisées par new :
3. Les variables
C1.couleur = Color.red ;
C2.couleur = Color.red ;
...
}
}
Remarque : On crée un objet Point2D. Sans cette création, le programme génère une
erreur (mémoire non allouée) lors de l’affectation d’un des champs d’un objet de la classe.
Ces variables sont globales pour une classe et pour toutes les instances de cette classe.
Les variables de classe sont utiles pour faire communiquer entre eux différents objets
d’une même classe ou pour définir des propriétés communes à un groupe d’objets de la
même classe. Pour différencier les variables d’objet des variables de classe on utilise le
mot-clé static.
Fichier "Point2D.java"
class Point2D
{
double x,y;
}
Fichier "Cercle.java"
class Cercle
{
Point2D centre = new Point2D();
double rayon;
static Color couleur;(*)
}
Fichier "Program.java"
class Program
{
public static void main (args[]) {
Cercle C1 = new Cercle() ;
Cercle C2 = new Cercle() ;
C1.centre.x = 3.45;
Enseignante : Mme I.JAOUANI Page 34
L2
C1.centre.y = 3.56;
Cercle.couleur = Color.red ;(**)
...
}
Remarque :
* Le champ couleur est une variable de classe
** On applique une couleur à tous les objets de la classe.
4. Les méthodes
Fichier "Point2D.java"
class Point2D {
double x,y;
}
Fichier "Cercle.java"
class Cercle {
Point2D centre = new Point2D ();
double rayon;
Color couleur;
void Move(double x ,double y) {
centre.x = centre.x + x;
centre.y = centre.y + y;
}
}
Fichier "Program.java"
class Program {
public void main (args[]) {
Cercle C = new Cercle() ;
C.centre.x = 3.45;
C.centre.y = 3.56;
C.Move(4.0,3.0) ;
...
}
}
Comme les variables de classe, les méthodes de classe (à déclarer en static) s’appliquent à
la toute classe et non à ses instances. Ces méthodes servent surtout à grouper au même
endroit, dans une classe, des méthodes à caractère général.
Par exemple, la classe Math définie dans java.lang contient de nombreuses méthodes
de classe. Il n’existe pas d’instance de la classe Math, mais on peut utiliser directement ses
méthodes. Par exemple la méthode max(…) :
int a = Math.max (x, y) ;
C.Move(4.0,3.0) ;
...
C.Move(2.0) ;
...
for (int i=1;i<=10;i++)
C.Move() ;
}
}
Appel des trois méthodes Move appliquée à l’objet C de la classe Cercle
Lorsque vous appelez une méthode dont les arguments comportent un ou plusieurs objets,
les variables qui sont passées au corps de la méthode sont passées par référence. Ceci
signifie qu’il n’y a pas de copie locale (à la méthode) de l’objet passé en paramètre. Par
conséquent, toute manipulation de l’objet à l’intérieur de la méthode affecte l’objet original.
Cette règle de passage des paramètres s’applique à tous les objets ainsi qu’aux tableaux.
Seul les variables de type simple (entiers, réels, booléens et caractères) sont passées par
valeur (on recopie localement la variable et on travaille sur cette copie).
Comme nous l'avons déjà dit en présentant le langage, on lance l'exécution d'un programme
Java en démarrant une machine virtuelle Java avec, en paramètre, le nom de la classe de
démarrage. Cette classe doit impérativement contenir une méthode main. Une fois que la
machine virtuelle s'est mise en place, elle lance le programme proprement dit par la première
instruction de la méthode main, et ce, sans instancier d'objet à partir de la classe de
démarrage. Ceci est possible car la méthode main est déclarée static : c'est à dire qu'elle
existe sans qu'il y ait eu instanciation. La tâche principale de cette méthode est alors
d'instancier des objets sur différentes classes afin que le programme puisse s’exécuter.
Comme la méthode main existe indépendamment de toute instance de classe, si elle doit
utiliser des attributs ou des méthodes de la classe, il faut que ces champs soient eux aussi
déclarés static, sans quoi, ils n'existent pas. Plus formellement, les méthodes déclarées
statiques, sur une classe, ne peuvent manipuler que des champs statiques.
De manière basique, on peut dire qu'un constructeur est une méthode, d'une classe donnée,
servant à créer des objets. Contrairement aux méthodes, un constructeur n'a pas de type de retour
et il a nécessairement le même nom que la classe dans laquelle il est défini. De même que les
autres méthodes, les constructeurs acceptent la surcharge. L'exemple suivant propose donc
quelques constructeurs pour nos classes déjà étudiées.
Fichier "Point2D.java"
class Point2D {
double x,y;
Point2D () { x=0.0, y=0.0 ; }
Fichier "Cercle.java"
7.2 Le destructeur
Nous venons donc de voir que des constructeurs pouvaient être fournis pour permettre la
création d'objets. Parallèlement, un destructeur (et un seul) peut être défini, pour être utilisé
lors de la destruction de l'objet. Celui-ci doit forcément se nommer finalize, il ne prend
aucun paramètre et ne renvoie aucun type (void). Voici un petit exemple :
class Point2D {
...
void finalize()
{
System.out.println("Objet point (2D) détruit");
}
...
}
Enseignante : Mme I.JAOUANI Page 41
L2
Un programme Java a besoin de mémoire pour pouvoir s'exécuter (en règle général, plus il en
a, mieux c'est). Comme on l'a déjà vu, l’opérateur new se charge d'allouer de la mémoire à la
demande. Une conséquence évidente est que si l'on ne libère pas la mémoire des objets
devenus inutiles, on peut rapidement en manquer. Le ramasse-miettes (Garbage Collector) se
charge de repérer ces objets inutiles, et de libérer la mémoire qu'ils utilisent inutilement. Il
opère de façon totalement automatisé, et dans la quasi totalité des cas, vous n'avez pas à vous
en soucier. N'oubliez pas que vous avez la possibilité de définir, par l'intermédiaire d’un
destructeur, des actions à effectuer en cas de destructions d'objet.
Ils se placent avant ou après le type de l'objet mais la convention veut qu'ils soient placés
avant. Ils s'appliquent aux :
Classes,
et/ou aux méthodes,
et/ou aux attributs.
Ils ne peuvent pas être utilisés pour qualifier des variables locales : seules les variables
d'instances et de classes peuvent en profiter.
Ils assurent le contrôle des conditions d'héritage, d'accès aux éléments et de modification
de données par les autres objets.
De nombreux langages orientés objet introduisent des attributs de visibilité pour réglementer
l'accès aux classes et aux objets, aux méthodes et aux données.
Dans Java, il y a quatre modificateurs qui peuvent être utilisés pour définir les attributs de
visibilité des entités (classes, méthodes ou attributs):
private,
protected,
public
default (ou l’absence de tout modificateur).
Modificateur Rôle
Public Une variable, méthode ou classe déclarée public est visible par tous les
autres objets.
Une seule classe public est permise par fichier et son nom doit correspondre
à celui du fichier.
Dans la philosophie orientée objet aucune donnée d'une classe ne devraient
être déclarée publique : il est préférable d'écrire des méthodes pour la
consulter et la modifier
par défaut : Il n'existe pas de mot clé pour définir ce niveau, qui est le niveau par défaut
package lorsqu'aucun modificateur n'est précisé.
friendly Cette déclaration permet à une entité (classe, méthode ou variable) d'être
visible par toutes les classes se trouvant dans le même package.
protected Si une classe, une méthode ou une variable est déclarée protected, seules les
méthodes présentes dans le même package que cette classe ou ses sous
classes pourront y accéder.
On ne peut pas qualifier une classe avec protected.
Private C'est le niveau de protection le plus fort. Les composants ne sont visibles
qu'à l'intérieur de la classe :
ils ne peuvent être modifiés que par des méthodes définies dans la classe
prévues à cet effet.
Les méthodes déclarée private ne peuvent pas être en même temps déclarée
abstract car elles ne peuvent pas être redéfinies dans les classes filles.
Le mot clé final s'applique aux variables de classe ou d'instance, aux méthodes et aux
classes. Il permet de rendre l'entité sur laquelle il s'applique non modifiable une fois qu'elle
est déclarée pour une méthode ou une classe et initialisée pour une variable.
Une variable qualifiée de final signifie que la valeur de la variable ne peut plus être modifiée
une fois que celle ci est initialisée. On ne peut pas déclarer de variables final locale à une
méthode.
Exemple :
Une fois la variable déclarée final initialisée, il n'est plus possible de modifier sa valeur.
Une vérification est opérée par le compilateur.
Exemple :
C:\>javac Constante1.java
Constante1.java:6: cannot assign a value to final variable constante
this.constante = 10;
^
1 error
Lorsque le modificateur final est ajouté à une classe, il est interdit de créer une classe
qui en hérite.
Fichier "TestReference.java"
class TestReference
{
public static void main (args[])
{
Cercle C1, C2 ;
C1 = new Cercle();
C2 =C1;
C1.rayon = 3.0;
System.out.println ("r1 = "+C1.rayon);
System.out.println ("r2 = "+C2.rayon);
}
}
à l’écran
r1 = 3.0
r2 = 3.0
Dans la première partie du programme, on déclare deux variables de type Cercle (C1 et C2),
on crée un objet Cercle affecté à C1 et on affecte à C2 la valeur de C1. Comme on peut le
constater par le résultat à l’écran, la variable d’instance x a été modifiée pour les deux objets.
L’affectation de la valeur de C1 à C2 n’a pas créé un nouvel objet mais simplement une
référence à l’objet pointé par C1 (Cf. figure ci-dessous). Pour créer deux objets distincts,
il faut utiliser l’opérateur new pour chacun des objets.
Objet Cercle
C1 centre.x : 0.0
centre.y : 0.0
C2 rayon = 3.0
couleur …
L’utilisation des références prend toute son importance lorsque les arguments sont
transmis aux méthodes.
Exercice 1 :
Il s'agit de modéliser un segment de droite dont les valeurs des deux extrémités sont entières.
Si on échange les deux extrémités, on considère qu'il s'agit encore du même segment. Les
opérations que l'on souhaite faire sur ce segment sont :
calculer sa longueur
savoir si un entier donné se trouve sur le segment (c'est-à-dire s'il est compris entre la
plus petite et la plus valeurs des extrémités du segment).
Il s'agit de modéliser un vecteur de Z2 dont l'origine est en (0, 0) (un tel vecteur est donc
caractérisé par deux nombres entiers relatifs). Les opérations que l'on souhaite faire sur ce
segment sont :
calculer sa longueur, par une méthode d'instance sans paramètre, nommée longueur, et
qui retourne cette longueur sous forme d'un double
savoir si le vecteur concerné est ou non plus petit qu'un autre un autre vecteur donné ;
on écrira pour cela une méthode d'instance nommée plusPetitQue qui recevra en
paramètre l'autre vecteur et qui retournera une variable de type boolean
additionner au vecteur concerné un autre vecteur ; on écrira pour cela une méthode
d'instance nommée addition qui recevra en paramètre l'autre vecteur et qui ne retournera
rien
additionner deux vecteurs donnés ; on écrira pour cela une méthode statique nommée
aussi addition (en utilisant ainsi la possibilité de la surcharge) qui recevra en paramètres
les deux vecteurs à additionner et qui retournera le résultat sous forme d'un objet de type
Vecteur
une méthode redéfinissant la méthode :
On créera une classe EssaiVecteur contenant une méthode main pour tester la classe Vecteur.
Les composantes des vecteurs à traiter dans les tests pourront être indiquées sur la ligne de
commande.
Chapitre IV
Chapitre 4 : Héritage
Vue d’ensemble
Objectifs
A la fin de cette leçon, l’étudiant sera capable de :
Comprendre le principe d’héritage
Comprendre l’héritage simple
Définir des constructeurs de la classe dérivée
Utiliser la redéfinition de fonctions dan/s les classes dérivées
Durée : 6 h
Pré-requis :
Algorithmique et structures de données 1
Atelier de programmation 1
Classes et objets
1. Introduction
L’héritage est une technique née du besoin de raffinement qui correspond à la situation suivante
: on dispose d'une classe A achevée, opérationnelle, définissant des objets satisfaisants, et il
nous faut définir une classe B qui en est une extension : les objets B ont tout ce qu'ont les objets
A plus quelques variables et méthodes ajoutées et/ou quelques méthodes
« améliorées » (on dira redéfinies).
Imaginons, par exemple, qu'on dispose d'une classe Article pour représenter les articles
caractérisés par le nom, le prix et la quantité et qu'il nous faille une classe Boisson dont les
instances sont des articles qui ont en plus un volume. Ces instances comportent donc tout ce qui
fait un article et, en plus la caractéristique Volume.
Si nous ne disposions que des outils expliqués dans les chapitres précédents, nous devrions
définir la classe Boisson en y dupliquant les informations qui se trouvent dans la définition de
la classe Article.
Classe Boisson
Classe Article
Nom
Nom Prix
Prix Qualité
Le mécanisme de l'héritage permet d'éviter cette duplication, en nous laissant déclarer dès le
commencement que la classe Boisson étend la classe Article et en possède donc tous les
attributs. De cette manière, il ne nous reste à définir que les membres spécifiques que la
deuxième classe (que nous appellerons la sous-classe) ajoute à la première (la super-classe).
Classe Article
Super-classe
Nom
Prix
Volume
2. Sous-classes et Super-classes
L'héritage est le mécanisme qui consiste à définir une classe nouvelle, dite classe dérivée
ou sous-classe, par extension d'une classe existante, appelée sa classe de base ou super-
classe. La sous-classe possède d'office tous les membres de la super-classe, auxquels elle
ajoute ses membres spécifiques.
L'héritage est indiqué par l'expression « extends SuperClasse » écrite au début de la
définition d'une classe.
Par exemple, définissons la classe Pixel comme sous-classe de la classe Point qui nous a
déjà servi d'exemple. Un pixel est un point, étendu par l'ajout d'une variable d'instance qui
représente une couleur (Color est une classe définie dans le paquet java.awt) :
class Point {
class principal{
int x, y;
Pixel pix = new Pixel();
...
pix.x = 2;
}
class Pixel extends Point { pix.y = 3;
En Java, l'héritage est simple : chaque classe possède au plus une super-classe directe. En
fait, il y a une classe particulière, nommée Object, qui n'a pas de super-classe, et toutes les
autres classes ont exactement une super-classe directe. Par conséquent, l'ensemble de toutes
les classes constitue une unique arborescence dont la racine est la classe Object.
Ainsi, les variables et méthodes qui composent un objet ne sont pas toutes définies dans la
classe de celui-ci : il y en a une partie dans cette classe, une partie dans sa super-classe, une
autre partie dans la super-classe de la super-classe, etc.
Un message ayant été envoyé à un objet, la méthode correspondante doit être recherchée
dans la classe de celui-ci ou, en cas d'échec, dans la super-classe de celle-là, puis dans la
super-classe de la super-classe, et ainsi de suite, en remontant le long de la branche de l'arbre
d'héritage, jusqu'à trouver une classe dans laquelle on a prévu de répondre au message en
question.
Que se passe-t-il lorsque des membres spécifiques de la sous-classe ont le même nom
que des membres hérités ? Deux cas :
1. Si les entités qui ont le même nom ont des rôles ou des signatures différentes,
alors c'est un cas de surcharge et il est traité comme s'il s'agissait de deux membres
de la même classe.
2. S'il s'agit au contraire de deux entités ayant le même rôle et, dans le cas des
méthodes, la même signature alors il y a masquage : dans la sous-classe, le membre
spécifique masque le membre hérité.
... ...
} }
Dans ces conditions, à l'intérieur d'une méthode de la classe Pixel, les expressions qualite
et this.qualite désignent le membre qualite spécifique de la classe Pixel. Mais les
expressions super.qualite et ((Point) this).qualite désignent toutes deux le membre qualite
hérité de la classe Point.
Il est facile de comprendre pourquoi la réponse à un appel comme unPixel.toString() peut être
vue comme une « amélioration » de la réponse à unPoint.toString() : si unPoint représente un
point et unPixel un pixel, les expressions :
System.out.println(unPoint);
System.out.println(unPixel);
L'initialisation d'un objet d'une sous-classe implique son initialisation en tant qu'objet de la
super-classe. Autrement dit, tout constructeur de la sous-classe commence nécessairement
par l'appel d'un constructeur de la super-classe.
Si le programmeur n'a rien prévu, ce sera le constructeur sans arguments de la super- classe,
qui doit donc exister. Mais on peut expliciter l'appel d'un constructeur de la super- classe
par l'instruction :
super(arguments);
Si elle est présente, cette instruction doit être la première du constructeur de la sous- classe.
Par exemple, si la classe Point n'a qu'un constructeur, à deux arguments :
Class Point {
int x, y;
Point(int x, int y) {
this.x = x;
this.y = y;
}
...
Alors le programmeur est obligé d'écrire un constructeur pour la classe Pixel, comme ceci :
class Pixel extends Point {
Color couleur;
Pixel(int x, int y, Color couleur) {
super(x, y);
this.couleur = couleur;
}
...
}
B b ;
b = (B)a ;
Pour savoir à quelle classe appartient un objet, on utilise l’opérateur « instanceof » qui
renvoie la valeur true ou false. Exemple :
if (a instanceof B) {
… ;
}
6. L’héritage multiple
La forme d’héritage étudiée précédemment s’appelle « l’héritage simple ». Dans un tel héritage,
chaque classe Java a une seule super-classe directe. Dans d’autres langages (notamment en
C++), les classes peuvent avoir plusieurs super-classes. Elles héritent alors de la combinaison
des variables et des méthodes de toutes leurs super-classes. Cela s’appelle
« l’héritage multiple ». Il s’agit d’un mécanisme puissant mais très complexe qui alourdit
souvent le code. Pour cette raison, Java se limite à l’héritage simple. Nous verrons bientôt qu’il
est possible de simuler l‘héritage multiple sans en avoir les inconvénients grâce au concept
d’interface.
On souhaite maintenant représenter des voitures. Les informations qui nous intéressent sont le
numéro d'immatriculation, la marque du véhicule et le nombre de fenêtres de celui-ci, qui
nous servira à calculer le montant d'une taxe.
1. Écrire une classe Voiture contenant un champ plaque de type Immatriculation, ainsi
que des champs marque et nombreDeFenetres repsectivement de type String et int.
2. Écrire les méthodes accesseurs de la classe puis une méthode toString() affichant la
marque, l'immatriculation et la taxe.
3. Écrire la méthode getMontantTaxe() qui calcule le montant de la taxe Alif selon la
formule 1000*nombreDeFenetres.
On veut maintenant représenter 2 types de véhicules: les voitures et les motos. Les
informations d'immatriculation et de marque sont utiles pour les deux types. En revanche, les
motos n'ont pas de fenêtre et le montant de la taxe pour une moto est de :
vitesseMaxi*vitesseMaxi .
Chapitre V
Vue d’ensemble
Objectifs
A la fin de cette leçon, l’étudient sera capable :
Introduire la notion de classes abstraite, les règles de définition et les intérêts pratiques
Introduire le concept d’interfaces, leurs intérêts pratiques et leurs relations avec
l’héritage
Durée : 3h
Pré-requis :
Algorithmique et structures de données 1
Atelier de programmation 1
Classes et objets
Héritage
1. Classes abstraites
Les classes abstraites sont des classes dont le seul but est de fournir des informations communes
aux sous classes. Elles peuvent contenir tout ce qu’une classe normale peut contenir (variables
et méthodes de classe, d’instance …).
Une classe abstraite comprend au moins une méthode abstraite. Elle est déclarée avec le mot
clé abstract.
Syntaxe :
Une classe abstraite est une classe qui n’est pas concrète (ayant toutes ses méthodes qui sont
implémentées). Elle ne peut pas être instanciée.
Une sous classe de la classe abstraite doit implémenter toutes les méthodes de la classe
abstraite.
Utilité :
Une classe abstraite est utilisée généralement pour faire des dérivations. Les classes
dérivées qui sont complètement implémentées peuvent être instanciées.
Remarques :
Les méthodes déclarées static, private et final ne peuvent pas être déclarées abstraites.
Une classe déclarée final ne peut pas être abstraite.
Les méthodes d’une classe abstraite doivent être publique.
Exemple :
Classe Figuregeom
}
public double RectangleLarg()
{
return l;
}
public double surface ()
{
return (l * L);
}
public double perimetre()
{
return (l + L)* 2;
}
}// fin de la classe Rectangle
2. Interfaces
Dans le cadre de Java, un type de données est une classe et un type de données abstrait est une
interface. Le mécanisme de l’interface est une généralisation de concept de classe abstraite.
2.1. Définition
Une interface est une classe qui ne comporte que des méthodes sans implémentation. On
trouve seulement les prototypes de ces fonctions (il faut mettre les noms des paramètres
formels). Une interface peut contenir des variables constantes de la forme : final int i = 10 ;
Au niveau de la syntaxe, on introduit une interface non plus avec le mot clé class mais avec le
mot clé interface.
La déclaration de l’interface
Le corps de l’interface
Syntaxe :
En-tête
interface Nom_Interface
{
Méthode 1 (liste d’arguments) ;
………..
Corps
Méthode 2 (liste d’arguments) ;
}
Une classe n’hérite pas d’une interface, mais elle l’implémente. On utilise le mot clé
implements.
Syntaxe :
{………..}
Une classe ne peut hériter que d’une seule classe (héritage simple), alors que l’on peut
implémenter plusieurs interfaces.
Syntaxe :
{………..}
Remarques :
Les modificateurs private ou protected ne sont jamais utilisés dans une interface.
L’interface est contenue dans un fichier à part.
Le nom d’une interface commence par I.
On peut avoir une classe sans méthodes mais elle implémente toutes les méthodes de
l’interface.
Exemples :
public interface I1
{
void m();
}
{………………}
Une interface définie une sorte de cahier de charges concernant un certain comportement
(ensemble d'opérations).
Chaque classe qui implémente une interface garantit à ses utilisateurs qu'elle est capable de
faire ce que l’interface spécifie via ses méthodes (assurer les opérations définies par
l'interface).
On va considérer une classe « CompteurAbstrait » caractérisé par les attributs et les méthodes
suivants :
Min : c’est la valeur minimale du compteur
Courant : c’est la valeur courant du compteur
RAZ : c’est la méthode qui permet de mettre à zéro le compteur
1 constructeur
Incrément : c’est la méthode abstraite qui permet d’incrémenter le compteur
Chapitre VI
Chapitre 6 : Le polymorphisme
Vue d’ensemble
Objectifs
A la fin de cette leçon, l’étudient sera capable :
Comprendre le principe de polymorphisme à travers des exemples
Comprendre la conversion des arguments en liaison avec le polymorphisme
Comprendre la conversion explicite des références en rapport avec le polymorphisme
Durée : 3 h
Pré-requis :
Algorithmique et structures de données 1
Atelier de programmation 1
Classes et objets
Héritage
Classes Abstraites et interfaces
1. Introduction
Il s’agit d’un concept extrêmement puissant en P.O.O., qui complète l’héritage. On peut
caractériser le polymorphisme en disant qu’il permet de manipuler des objets sans en connaître
(tout à fait) le type.
Par exemple, on pourra construire un tableau d’objets les uns étant de type Point, les autres
étant de type Pointcol (dérivé de Point) et appeler la méthode affiche pour chacun des objets
du tableau. Chaque objet réagira en fonction de son propre type.
Mais il se trouve que Java autorise ce genre d’affectation (p étant toujours de type Point)
p=new Pointcol(4,8,(byte)2); // p de type Point contient la référence
// à un objet de type Pointcol
La situation correspondante est la suivante :
D’une manière générale, Java permet d’affecter à une variable objet non seulement la référence
à un objet du type correspondant, mais aussi une référence à un objet d’un type dérivé.
On peut dire qu’on est en présence d’une conversion implicite (légale) d’une référence à un
type classe T en une référence à un type ascendant de T; on parle aussi de compatibilité par
affectation entre un type classe et un type ascendant.
Considérons maintenant ces instructions :
Point p=new Point(3,5);
p.affiche(); // appelle la méthode affiche de la classe Point
p=new Pointcol(4,8,2);
p.affiche(); // appelle la méthode affiche de la classe Pointcol
Dans la dernière instruction, la variable p est de type Point, alors que l’objet référencé par p
est de type Pointcol. L’instruction p.affiche()appelle alors la méthode affiche de
la classe Pointcol.
Autrement dit, elle se fonde, non pas sur le type de la variable p, mais sur le type effectif de
l’objet référencé par p au moment de l’appel.
Ce choix d’une méthode au moment de l’exécution (et non plus de la compilation) porte
généralement le nom de ligature dynamique (ou encore de liaison dynamique).
Exemple 1
Voici un premier exemple intégrant les situations exposées ci-dessus dans un programme
complet :
class Point
{
private int x, y ;
public Point (int x, int y)
{
this.x = x ; this.y = y ;
}
public void deplace (int dx, int dy)
{
x += dx ; y += dy ;
}
public void affiche ()
{
System.out.println ("Je suis en " + x + " " + y) ;
}
}
}
public class Poly
{
public static void main (String args[])
{
Point p=new Point(3,5);
p.affiche(); // appelle affiche de Point
Pointcol pc=new Pointcol(4,8,(byte)2);
p=pc ; //p de type Point, référence un objet de type Pointcol
p.affiche();//on appelle affiche de Pointcol
p=new Point(5,7); //p référence à nouveau un objet de type Point
p.affiche(); // on appelle affiche de Point
}
}
Exemple 2 :
Créer un tableau "hétérogène" d’objets, c’est-à-dire dans lequel les éléments peuvent être de
type différent.
public class TabHeter
{
public static void main(String args[])
{
Point tabPts[]=new Point[4];
tabPts[0]=new Point(0,2);
tabPts[1]=new Pointcol (1, 5, (byte)3);
tabPts[2]=new Pointcol (2, 8, (byte)9);
tabPts[3]=new Point (1, 2);
for (int i=0;i<tabPts.length;i++)
tabPts[i].affiche();
}
}
Les affectations suivantes sont légales : a=b; a=c;a=d;a=e;a=f; b=d; b=e; c=f;
4. Redéfinition et surdéfinition
Par essence, le polymorphisme se fonde sur la redéfinition des méthodes. Mais il est aussi
possible de surdéfinir une méthode.
Exemple :
class A
{
public void f(float x) { ...... }
.....
}
class B extends A
{
public void f(float x) { ..... } // redéfinition de f de A
public void f(int n) { ..... } // surdéfinition de f pour A et B
.....
}
A a=new A(. );
B b=new B(. );
int n;
a.f(n); // appelle f (float) de A (ce qui est logique)
b.f(n); // appelle f(int) de B comme on s’y attend
a=b; // a contient une référence sur un objet de type B
a.f(n); // appelle f(float) de B et non f(int)
Ainsi, bien que les instructions b.f(n) et a.f(n) appliquent toutes les deux une méthode
f à un objet de type B, elles n’appellent pas la même méthode.
Voyons plus précisément pourquoi.
À ce stade donc, la signature de la méthode et son type de retour sont entièrement figés. Lors
de l’exécution, on se fonde sur le type de l’objet référencé par a pour rechercher une méthode
ayant la signature et le type de retour voulus.
On aboutit alors à la méthode void f(float x) de B, et ce malgré la présence
(également dans B) d’une méthode qui serait mieux adaptée au type de l’argument effectif.
Ainsi, malgré son aspect ligature dynamique, le polymorphisme se fonde sur une signature
et un type de retour définis à la compilation (et qui ne seront donc pas remis en question lors
de l’exécution).
Exercice 1
Quels résultats fournit le programme suivant ?
class A
{
public void affiche() { System.out.print("Je suis un A "); }
}
class B extends A {}
class C extends A
{
public void affiche() { System.out.print("Je suis un C "); }
}
class D extends C
{
public void affiche() { System.out.print("Je suis un D "); }
}
class E extends B {}
class F extends C {}
Certaines possibilités d’affectation entre objets des types classes A, B, C, D, E et F ne figurent pas dans le
programme ci-dessus. Pourquoi ?
Exercice 2
Quels résultats fournit le programme suivant ?
class A
{
public void f(double x)
{
System.out.print("A.f(double=" + x +") ");
}
}
class B extends A {}
class C extends A
{
public void f(long q)
{
System.out.print("C.f(long=" + q + ") ");
}
}
class D extends C
{
public void f(int n)
{
System.out.print("D.f(int=" + n + ") ");
}
}
class F extends C
{
public void f(float x)
{
System.out.print("F.f(float=" + x + ") ");
System.out.println("** A ** ");
A a=new A(); a.f(bb); a.f(x); System.out.println();
System.out.println("** B ** ");
B b=new B(); b.f(bb); b.f(x); System.out.println();
a=b; a.f(bb);a.f(x);System.out.println() ;
System.out.println("** C ** ");
C c=new C(); c.f(bb); c.f(q); c.f(x); System.out.println();
a=c; a.f(bb); a.f(q); a.f(x); System.out.println();
System.out.println("** D ** ");
D d=new D(); d.f(bb); c.f(q); c.f(y); System.out.println();
a=c; a.f(bb); a.f(q); a.f(y); System.out.println();
System.out.println("** F ** ");
F f=new F(); f.f(bb); f.f(n); f.f(x); f.f(y); System.out.println();
a=f; a.f(bb);a.f(n); a.f(x); a.f(y); System.out.println();
c = f; c.f(bb); c.f(n); c.f(x); c.f(y);
}
}
Exercice 3
Soient les classes Point et PointNom ainsi définies :
class Point
private int x, y ;
}
Chapitre 7
Vue d’ensemble
Le but de cette dernière leçon est d’introduire la notion d’exception en langage java
Objectifs :
Introduire la notion d’exception, les règles d’utilisation et de définition des
exceptions
Distinguer entre les exceptions prédéfinies et les exceptions définies par les
utilisateurs
Durée : 1.5 h
Pré-requis :
Algorithmique et structures de données 1
Atelier de programmation 1
Classes et objets
1. Introduction
Lors de la détection d'une erreur, un objet qui hérite de la classe Exception est créé (on dit
qu'une exception est levée) et propagé à travers la pile d'exécution jusqu'à ce qu'il soit traité.
Exemple d’exception (division par 0): une exception levée à l'exécution non capturée
Résultat :
C:>java TestException
Exception in thread "main" java.lang.ArithmeticException: /
by zero
at tests.TestException.main(TestException.java:23)
Si dans un bloc de code, on fait appel à une méthode qui peut potentiellement générer
une exception, on doit soit essayer de la récupérer avec try/catch, soit ajouter le mot clé
throws dans la déclaration du bloc. Si on ne le fait pas, il y a une erreur à la compilation. Les
* Le bloc try rassemble les appels de méthodes susceptibles de produire des erreurs ou des
exceptions. L'instruction try est suivie d'instructions entre des accolades.
Exemple :
try {
operation_risquée1;
opération_risquée2;
}
catch (ExceptionInteressante e)
{
traitements
} catch (ExceptionParticulière e) {
traitements
} catch (Exception e) {
traitements
} finally {
traitement_pour_terminer_proprement;
}
ignorée. Une telle utilisation de l'instruction try/catch n'est pas une bonne pratique : il est
préférable de toujours apporter un traitement adapté lors de la capture d'une exception.
S'il y a plusieurs types d'erreurs et d'exceptions à intercepter, il faut définir autant de bloc
catch que de type d'événement. Par type d'exception, il faut comprendre « qui est du type de la
classe de l'exception ou d'une de ses sous classes ». Ainsi dans l'ordre séquentiel des clauses
catch, un type d'exception de ne doit pas venir après un type d'une exception d'une super
classe. Il faut faire attention à l'ordre des clauses catch pour traiter en premier les exceptions
les plus précises (sous classes) avant les exceptions plus générales. Un message d'erreur est
émis par le compilateur dans le cas contraire.
Exemple : erreur à la compilation car Exception est traité en premier alors que
ArithmeticException est une sous classe de Exception
Résultat :
C:\tests>javac TestException.java
TestException.java:11: catch not reached.
catch (ArithmeticException e) {
^
1 error
Si l'exception générée est une instance de la classe déclarée dans la clause catch ou
d'une classe dérivée, alors on exécute le bloc associé. Si l'exception n'est pas traitée par un
bloc catch, elle sera transmise au bloc de niveau supérieur. Si l'on ne se trouve pas dans un
autre bloc try, on quitte la méthode en cours, qui régénère à son tour une exception dans la
méthode appelante.
L'exécution totale du bloc try et d'un bloc d'une clause catch sont mutuellement
exclusives : si une exception est levée, l'exécution du bloc try est arrêtée et si elle existe, la
clause catch adéquate est exécutée.
*La clause finally définit un bloc qui sera toujours exécuté, qu'une exception soit levée ou
non. Ce bloc est facultatif. Il est aussi exécuté si dans le bloc try il y a une instruction break
ou continue.
3. La classe Throwable
Cette classe descend directement de la classe Object : c'est la classe de base pour le
traitement des erreurs. Cette classe possède deux constructeurs :
Méthode Rôle
Throwable()
Méthodes Rôle
Exemple:
Résultat :
C:>java TestException
getmessage
/ by zero
toString
java.lang.ArithmeticException: / by zero
printStackTrace
java.lang.ArithmeticException: / by zero
at tests.TestException.main(TestException.java:24)
Ces trois classes descendent de Throwable : en fait, toutes les exceptions dérivent de la
classe Throwable.
La classe Error représente une erreur grave intervenue dans la machine virtuelle Java
ou dans un sous système Java. L'application Java s'arrête instantanément dès l'apparition d'une
exception de la classe Error.
La classe Exception représente des erreurs moins graves. Les exceptions héritant de
classe RuntimeException n'ont pas besoin d'être détectées impérativement par des blocs
try/catch.
Pour générer une exception, il suffit d'utiliser le mot clé throw, suivi d'un objet dont la
classe dérive de Throwable. Si l'on veut générer une exception dans une méthode avec
throw, il faut l'indiquer dans la déclaration de la méthode, en utilisant le mot clé throws.
En cas de nécessité, on peut créer ses propres exceptions. Elles descendent des classes
Exception ou RunTimeException mais pas de la classe Error. Il est préférable (par
convention) d'inclure le mot « Exception » dans le nom de la nouvelle classe.
Exemple :
catch (SaisieErroneeException e) {
System.out.println("Chaine2 saisie erronee");
};
}
}
Les méthodes pouvant lever des exceptions doivent inclure une clause throws
nom_exception dans leur en tête. L'objectif est double : avoir une valeur documentaire et
préciser au compilateur que cette méthode pourra lever cette exception et que toute méthode
qui l'appelle devra prendre en compte cette exception (traitement ou propagation).
Java n'oblige la déclaration des exceptions dans l'en tête de la méthode que pour les
exceptions dites contrôlées (checked). Les exceptions non contrôlées (unchecked) peuvent
être capturées mais n'ont pas à être déclarées. Les exceptions et erreurs qui héritent de
RunTimeException et de Error sont non contrôlées. Toutes les autres exceptions sont
contrôlées.
Il est préférable d'utiliser les exceptions fournies par Java lorsque qu'une de ces exceptions
répond au besoin plutôt que de définir sa propre exception.
Error : ces exceptions concernent des problèmes liés à l'environnement. Elles héritent
de la classe Error (exemple : OutOfMemoryError)
RuntimeException : ces exceptions concernent des erreurs de programmation qui
peuvent survenir à de no
mbreux endroits dans le code (exemple : NullPointerException). Elles héritent de la
classe RuntimeException
Checked exception : ces exceptions doivent être traitées ou propagées. Toutes les
exceptions qui n'appartiennent pas aux catégories précédentes sont de ce type
Les exceptions de type Error et RuntimeException sont dites unchecked exceptions car les
méthodes n'ont pas d'obligation à les traiter ou déclarer leur propagation explicitement. Ceci
se justifie par le fait que leur levée n'est pas facilement prédictible.
Il n'est pas recommandé de créer ces propres exceptions en dérivant d'une exception de type
unchecked (classe de type RuntimeException). Même si cela peut sembler plus facile
puisqu'il n'est pas obligatoire de déclarer leur propagation, cela peut engendrer certaines
difficultés, notamment :
Proposition d’examens
« Énoncés/Corrections »
Des articles : Ce sont des Documents possédant une caractéristique complémentaire : le nom
d’auteur.
Des livres : Ce sont des articles possédant une caractéristique complémentaire : le nom de
l’éditeur.
Des périodiques : Ce sont des documents possédant une caractéristique complémentaire : le
nombre d’édition.
2. Implémenter les classes : Article, Livre et Périodique.
Chaque document est inséré lors de sa création dans une bibliothèque. C’est pourquoi on doit
aussi implémenter la classe Bibliothèque caractérisée par les attributs et les méthodes suivantes
:
Listdoc : c’est un tableau de documents.
Nombre de documents : c’est un attribut qui indique le nombre de documents ajoutés dans la
bibliothèque.
Un constructeur qui permet d’initialiser une bibliothèque en indiquant sa capacité maximale.
void ajout_doc (Document d) : c’est une méthode qui permet d’ajouter un document dans la
bibliothèque en respectant l’ordre des numéros d’identification.
void supprim_doc (int num) : c’est une méthode qui supprime un document de la
bibliothèque à partir de son numéro d’identification.
void Inventaire_doc() : c’est une méthode qui édite la liste de tous les documents avec leurs
types.
int getNombre_document() : retourne le nombre de documents.
3. Implémenter la classe Bibliothèque.
4. Ecrire la classe TestBibliothèque qui permet de tester les classes déjà construites : instancier
la classe bibliothèque, ajouter différents types de documents, faire l’inventaire et supprimer le
premier document ajouté.
Titre = leTitre ;
NB_P = leNB_P ;
}
Abstract void Edition() ; // 0.5
Abstract String getType() ; //0.5
//total 2 points
Class Article extends Document //0.25
{
String NomH; //0.25
Article ( String Titre, int ID, int NB_P, String NomH)//0.5
{
Super(Titre,ID,NB_P) ;
This.NomH = NomH ;
}
String gettype ()//0.5
{
Return (“Article”);
}
Void Edition()//0.5
{
System.out.println (“le titre de l’article est “ + titre + “ identifier par » + ID + « le total des
pages est » + NB_P) ;
}
}//fin class Article
//total bareme 2 points
Class Livre extends Articles {//0.25
String NomE;//0.25
Livre (String Titre, int ID, int NB_P, String NomH, String NomE)//0.5
{
}
void Inventaire_doc() //1point
{
For(int i = num ; i < NbDoc ; i++)
{
Listdoc[i].Edition();
}
}
int getNombre_document() //0.5
{
Return NbDoc ;
}
}//fin class Bibliotheque
//total 2.5 points
Class TestBibliotheque
{
1/ Avec quel mot clé peut-on accéder aux méthodes d'une classe mère lorsque nous créons
une classe héritée ?
a- Super.
b- Hyper.
c- Ultra.
2/ Dans quel cas doit-on utiliser une classe abstraite ?
a- Pour faire une classe mère.
b- Pour faire une classe mère qui ne doit pas être instanciée.
c- Pour faire une classe héritée.
3/ Que va afficher ce code ?
public class A{
public A(){ System.out.println("1"); }
}
public class B extends A{}
public class Test {
public static void main(String[] args){B b = new B();}
}
a- Rien.
b- 1.
c- Erreur de compilation.
4/ Peut-on instancier une interface ?
a- Oui
b- Non
c- Je ne sais pas.
Une société vend des articles de papeterie, parmi lesquels, on trouve ce qui suit :
des stylos décrits par :
1. une référence
2. un descriptif
3. une marque
4. un prix unitaire
5. une couleur
des ramettes de papier décrites par
1.une référence
2.un descriptif
3.une marque
4.un prix unitaire
5.le grammage du papier (par exemple, 80 g/m²)
Travail demandé :
1. Écrire une classe « Article », sachant qu’un article est caractérisé par :
un attribut référence de type entier
un attribut descriptif de type chaîne de caractères
un attribut marque de type chaîne de caractères
un attribut prix unitaire de type double
un constructeur qui permet d’initialiser les variables d’instance de la classe Article.
5. Écrire une classe « Lot » qui contient un tableau d’objets « Article », et un attribut
nbArticles. La classe « Lot » implémente l’interface «Facturable» et comporte les
méthodes ci-dessous :
6. Écrire une classe de test « TestLot » qui permet de : (voir sortie console)
créer un objet Lot A comportant 7 Stylo et 3 Ramette (pour ajouter un article, utiliser
l’appel à la méthode ajouterArticle …)
afficher la description de chaque article,
calculer puis afficher la facture du lot,
Sortie console :
article : ref:1 desc:stylo marq:bic pu:1.0 coul:5
article : ref:1 desc:stylo marq:bic pu:1.0 coul:5
article : ref:1 desc:stylo marq:bic pu:1.0 coul:5
article : ref:1 desc:stylo marq:bic pu:1.0 coul:5
article : ref:1 desc:stylo marq:bic pu:1.0 coul:5
article : ref:1 desc:stylo marq:bic pu:1.0 coul:5
article : ref:1 desc:stylo marq:bic pu:1.0 coul:5
article : ref:2 desc:Rame Papier marq:Paperus pu:6.0 grammage:3
article : ref:2 desc:Rame Papier marq:Paperus pu:6.0 grammage:3
article : ref:2 desc:Rame Papier marq:Paperus pu:6.0 grammage:3
la facture est de : 25.0 dinars
la facture est de : 19.0 dinars
1/ Avec quel mot clé peut-on accéder aux méthodes d'une classe mère lorsque nous créons une classe
fille ? (1 pt)
d- Super.
e- Hyper.
f- Ultra.
2/ Créer une classe abstraite nous permet de ? (1 pt)
d- Créer une classe mère.
e- Créer une classe qui n’est pas directement instanciable.
f- Créer une classe fille.
3/ Que va afficher ce code ? (1 pt)
public class A{
public A(){ System.out.println("1"); }
}
public class B extends A{}
public class Test {
public static void main(String[] args){B b = new B();}
}
d- Rien.
e- 1.
d- Oui
e- Non
f- Je ne sais pas.
5/ Quand est-ce qu’on utilise le mot clé static pour une méthode en Java ? (1 pt)
Une méthode précédée par le mot clé « static » est dite statique (méthode de classe), cette
dernière peut être appelée même sans avoir instancié la classe. Une méthode statique ne peut
accéder qu'à des attributs et méthodes statiques.
@Override
public String toString() {
return "description=" + description + ", marque=" + marque
+ ", prix=" + prix + ", reference=" + ref;
package com.poo.exam;
package com.poo.exam;
package com.poo.exam;
package com.poo.exam;
for(int i=0;i<nbArticles;i++) {
if(articles[i]!= null) {
facture += articles[i].prix;
}
}
return facture;
}
package com.poo.exam;
============================ FIN=============================
package com.poo.exam;
package com.poo.exam;
package com.poo.exam;
package com.poo.exam;
Bibliographie
[1] : « JAVA 6 Les fondamentaux du langage java » Thierry GROUSSARD, édition ENI Mars 2009
[5] : http://www.jmdoudoux.fr/java/dej/index.htm
[6] : www.Technologuepro.com
[7] : http://java.developpez.com/