Cours Java
Cours Java
Licence Fondamentale
SMI – S5
El Mostafa DAOUDI
Département de Mathématiques et d’Informatique,
Faculté des Sciences
Université Mohammed Premier
Oujda
[email protected]
Septembre 2012
El Mostafa DAOUDI- p. 1
Quelques Références:
- Cours JAVA SMI S5, Daoudi 2011/2012
Livre:
- Titre: Programmer en JAVA ,
AuteurClaude Delnoy,
Editeur: Eyrolles
- Thinking in Java, Bruce Eckel
Ressources Internet:
- http ://www.java.sun.com
- Richard Grin: http://deptinfo.unice.fr/~grin
- Cours Mickaël BARON - 2007
- Cours Interface graphique en Java API swing, Juliette Dibie-Barthélemy mai
2005
- …..
El Mostafa DAOUDI- p. 2
1
Ch I. Introduction générale au langage Java
I. Introduction
• Java est un langage orienté objet: l'entité de base de tout
code Java est la classe
• Créé en 1995 par Sun Microsystems
• Sa syntaxe est proche du langage C
• Il est fourni avec le JDK (Java Developpment Kit)
– Outils de développement
– Ensemble de paquetages très riches et très variés
• Multi-tâches (threads)
• Portable grâce à l’exécution par une machine virtuelle
El Mostafa DAOUDI- p. 3
El Mostafa DAOUDI- p. 4
2
II. Environnement de Programmation
1. Compilation
• La compilation d’un programme Java ne traduit pas
directement le code source en fichier exécutable. Elle traduit
d’abord le code source en un code intermédiaire appelé
«bytecode». C’est le bytecode qui sera ensuite exécuté par une
machine virtuelle (JVM ; Java Virtual Machine). Ceci permet
de rendre le code indépendant de la machine qui va exécuter le
programme.
El Mostafa DAOUDI- p. 6
3
2. Exécution du bytecode
• Le bytecode doit être exécuté par une JVM. Cette JVM n'existe pas;
elle est simulée par un programme qui
– lit les instructions (en bytecode) du programme .class,
– les traduit dans le langage machine relatif à la machine sur laquelle
il sera exécuté.
– Lance leur exécution
• Pour exécuter, Sun fournit le programme java qui simule une JVM. Il
suffira d’utiliser la commande:
java MonPremProg
El Mostafa DAOUDI- p. 7
El Mostafa DAOUDI- p. 8
4
Dans le cas de l’environnement JDK de SUN.
El Mostafa DAOUDI- p. 9
El Mostafa DAOUDI- p. 10
5
• De manière générale, dans tout programme destiné à être
exécuté doit contenir une méthode particulière nommée
main() définie de la manière suivante:
public static void main(String args[]) {
/* corps de la méthode */
}
• Le paramètre args de la méthode main() est un tableau
d’objets de type String. Il est exigé par le compilateur Java.
• La classe contenant la méthode main() doit obligatoirement
être public afin que la machine virtuelle y accède.
• Dans l’exemple précédent, le contenu de la classe
MonPremProg est réduit à la définition d’une méthode
main().
El Mostafa DAOUDI- p. 11
El Mostafa DAOUDI- p. 12
6
Ch. II Les classes et les Objets
I. Généralité sur la Programmation Orientée Objet
• La Programmation Orientée Objet (POO) propose une méthodologie de
programmation centrée sur les objets, où un objet peut être vu comme une
entité regroupant un ensemble de données et de méthodes de traitement.
• Le programmeur
- Doit d’abord identifier les objets qui doivent être utilisé (ou manipulé) par
le programme: on commence par décider quels objets doivent être inclus
dans le programme.
- Il va ensuite écrire les traitements, en associant chaque traitement à un
objet donné.
Il s'agit donc :
- de déterminer les objets présents dans le programme.
- d'identifier leurs données .
- de définir les traitements à faire sur ses objets .
El Mostafa DAOUDI- p. 13
El Mostafa DAOUDI- p. 14
7
II. Les classes
Une classe (ou type d’objets) représente une famille d’objets qui
partagent des propriétés communes.
Une classe regroupe les objets qui ont :
- La même structure (même ensemble d’attributs).
- Le même comportement (même méthodes).
El Mostafa DAOUDI- p. 16
8
Exemple: Rectangle est une classe utilisée pour créer des objets
représentant des rectangles particuliers.
• Elle regroupe 4 données de type réel qui caractérisent le rectangle:
longueur , largeur et origine (x,y) (la position en abscisse et en
ordonnée de son origine).
• On suppose qu’on peut effectuer les opérations de déplacement et de
calcul de la surface du rectangle.
• Les symboles + et – sont les spécificateurs d’accès (voir plus loins)
Exemple (notation UML)
El Mostafa DAOUDI- p. 17
El Mostafa DAOUDI- p. 18
9
Exemple:
Soit « Rectangle » une classe utilisée pour créer des objets représentant des
rectangles particuliers. Un objet de type « Rectangle » est caractérisé
par:
– La longueur de ses cotés.
– Sa position dans le plan: cette position peut être définie par la
position de son centre dans le plan. On suppose aussi que les cotés
du rectangle sont parallèles à l’axe des abscisses et l’axe des
ordonnées.
On suppose qu’on peut effectuer sur un objet de type rectangle, les
opérations suivantes:
– calcul de la surface
– déplacement dans le plan
El Mostafa DAOUDI- p. 19
10
III. Création et manipulation d’Objets
1. Introduction
• Une fois la classe est définie, on peut créer des objets
(variables).
Donc chaque objet est une variable d’une classe. Il a son
espace mémoire, il admet une valeur propre à chaque attribut.
Les valeurs des attribut caractérisent l’état de l’objet.
El Mostafa DAOUDI- p. 21
El Mostafa DAOUDI- p. 22
11
• Les valeurs des attributs peuvent être différents.
Chaque instance d’une classe possède ses propres valeurs pour chaque attribut
(chaque objet a son propre état).
Rectangle
« instance»
El Mostafa DAOUDI- p. 23
Syntaxe:
NomDeClasse1 objetId;
NomDeClasse2 objetId1, objetId2,….;
El Mostafa DAOUDI- p. 24
12
Attention:
- La déclaration d’une variable de type primitif réserve un emplacement
mémoire pour stocker la variable.
- Par contre, la déclaration d’un objet, ne réserve pas une place mémoire
pour l’objet, mais seulement un emplacement pour une référence à cet
objet.
les objets sont manipulés avec des références
El Mostafa DAOUDI- p. 25
Exemple:
Considérons la classe ClasseTest
class ClasseTest {
// corps de la classe ClasseTest
}
l’instruction:
ClasseTest objA;
- Déclare objA comme objet (variable) de type ClasseTest
- Définit le nom et le type de l’objet.
- Déclare que la variable objA est une référence à un objet de la classe
ClasseTest. Cela veut dire qu’on va utiliser une variable objA qui
référencera un objet de la classe ClasseTest.
- Aucun objet n’est créé: un objet seulement déclaré, vaut « null ».
objA
null
El Mostafa DAOUDI- p. 26
13
2.2. Création d’un objet
Après la déclaration d’une variable, on doit faire la création (et
allocation) de la mémoire de l’objet qui sera référencé par cette
variable.
- La création doit être demandé explicitement dans le programme en
faisant appel à l’opérateur new.
- La création réserve de la mémoire pour stocker l’objet et initialise les
attributs.
L’expression new NomDeClasse() créée un emplacement pour
stocker un objet de type NomDeClasse.
Important:
- avant d’utiliser un objet on doit le créer.
- la déclaration seule d’un objet, ne nous permet pas de l’utiliser.
El Mostafa DAOUDI- p. 27
Exemple
class ClasseTest {
/* Corps de la classe ClasseTest */
}
En générale:
1. Chaque objet met ses données membres dans sa propre zone mémoire.
2. En général, les données membres ne sont partagées entre les objets de la
même classe.
El Mostafa DAOUDI- p. 28
14
Exemple : Considérons la classe rectangle
public class Rectangle{
int longueur;
int largeur;
int x;
int y;
public static void main (String args[]) {
Rectangle rectangleR1; /* déclare une référence sur l’objet rectangleR1 */
rectangleR1 = new Rectangle(); /* création de l’objet rectangleR1 */
// rectangle R1 est une instance de la classe Rectangle
// Les deux expressions peuvent être remplacées par :
// Rectangle rectangleR1=new Rectangle();
}
}
El Mostafa DAOUDI- p. 29
El Mostafa DAOUDI- p. 30
15
Attention: Cette garanti d’initialisation par
défaut ne s’applique pas aux variables locales
(variables déclarée dans un bloc: par exemple
les variables locales d’une méthode) (voir
plus loin).
El Mostafa DAOUDI- p. 31
Syntaxe:
typeRetour nomMethode ( « Liste des paramètres » ) {
/*
corps de la méthode: les instructions décrivant la méthode
*/
}
El Mostafa DAOUDI- p. 32
16
- nomMethode : c’est le nom de la méthode
- « Liste des paramètres » : liste des arguments de la méthode.
Elle définit les types et les noms des informations qu’on
souhaite passer à la méthode lors de son appel.
- typeRetour : c’est le type de la valeur qui sera retournée par
la méthode après son appel. Si la méthode ne fournit aucun
résultat, alors typeRetour est remplacé par le mot clé void.
Remarque:
Dans le cas où la méthode retourne une valeur, la valeur
retournée par la fonction doit être spécifiée dans le corps de la
méthode par l’instruction de retour:
return expression;
ou
return; // (possible uniquement pour une fonction de type void)
El Mostafa DAOUDI- p. 33
El Mostafa DAOUDI- p. 34
17
Exemple:
class ClasseTest {
void methode1(int j){
j+=12;
}
void methode2() {
int j = 3;
methode1(j);
System.out.println(j=" + j); // j=3
}
}
El Mostafa DAOUDI- p. 35
• Remarques:
- La signature d’une méthode est: le nom de la méthode et l’ensemble
des types de ses paramètres.
- En Java, le type de la valeur de retour de la méthode ne fait pas partie
de sa signature.
El Mostafa DAOUDI- p. 36
18
Considérons l’exemple suivant ou la classe ClasseTest est
dotée de 2 méthodes calcMoyenne:
- La première a deux arguments de type double
- La deuxième a trois arguments de type double
El Mostafa DAOUDI- p. 37
class ClasseTest{
public double calcMoyenne(double m1, float m2) {
return (m1+m2)/2;
}
public float calcMoyenne(double m1, double m2, double m3) {
return (m1+m2+m3)/3;
}
}
19
V. Accès aux membres d’un objet
1. Accès aux attributs(données membres)
Considérons la classe ClassTest suivante:
class ClasseTest {
double x;
boolean b;
}
El Mostafa DAOUDI- p. 39
Une fois l’objet est créé, on peut accéder à ses données membres
de la manière suivante: on indique le nom de l’objet suivi par un
point, suivi par le nom de l’attribut comme suit:
nomObjet.nomAttibut
où:
nomObjet = nom de la référence à l’objet (nom de l’objet)
nomAttribut =nom de la donnée membre (nom de l’attribut).
El Mostafa DAOUDI- p. 40
20
2. Accès aux méthodes: appels des méthodes
• Les méthodes ne peuvent être définies que comme
des composante d’une classe.
• Une méthode ne peut être appelée que pour un objet.
• L’appel d’une méthode pour un objet se réalise de la
manière suivante: on indique le nom de l’objet suivi
d’un point, suivi du nom de la méthode et de sa liste
d’arguments:
nomObjet.nomMethode(arg1, ….).
où
nomObjet: nom de l’objet
nomMethode: nom de la méthode.
El Mostafa DAOUDI- p. 41
class ClasseTest {
// attributs
int f(double x) {
int n;
// corps de la fonction f()
return n;
}
}
El Mostafa DAOUDI- p. 42
21
Exemple 2: Considérons la classe Rectangle dotée de la méthode initialise qui
permet d’affecter des valeurs à l’origine (aux attributs x et y).
public class Rectangle{
int longueur, largeur;
int x,y;
void initialise_origine(int x0, int y0) {
x=x0; y=y0;
}
public static void main (String args[]) {
Rectangle r1;
r1.longueur=4; r1.largeur=2;
r1. initialise_origine(0,0); // affecte 0 aux attribut x et y
// Affiche l’erreur : NullPointException()
/* En effet l’objet r1 est seulement déclaré. Il n’est pas encore créé.
Avant de l’utiliser, il faut tout d’abord le créer */
}
}
El Mostafa DAOUDI- p. 43
El Mostafa DAOUDI- p. 44
22
VI. Encapsulation
• Une classe permet d’envelopper les objets : Un objet est vu par le
reste du programme comme une entité opaque.
• L'enveloppement [wrapping] des attributs et méthodes à l'intérieur
des classes plus (+) le contrôle d'accès aux membre de l’objet est
appelé encapsulation.
• Le contrôle d'accès aux membres de l’objet est appelé cacher
l'implémentation: Les membres publiques sont vus de l'extérieur
mais les membres privés sont cachés.
• L'encapsulation est un mécanisme consistant à rassembler les
données et les méthodes au sein d'une structure en cachant
l'implémentation de l'objet, c'est-à-dire en empêchant l'accès aux
données par un autre moyen que les services proposés.
El Mostafa DAOUDI- p. 45
El Mostafa DAOUDI- p. 46
23
Spécificateurs d’accès:
L'encapsulation permet de définir 3 niveaux de visibilité des
éléments de la classe. Ces 3 niveaux de visibilité (public, private
et protected) définissent les droits d'accès aux données suivant le
type d’accès:
El Mostafa DAOUDI- p. 47
El Mostafa DAOUDI- p. 48
24
Exemple 1: accès pour modification depuis l’extérieur d’un champs
class ClasseTest {
public int x;
private int y;
public void initialise (int i, int j){
x=i;
y=j; // ok: accès depuis l’intérieur (depuis la classe elle-même) à l’attribut private y
}
}
public class TestA{ // fichier source de nom TestA.java
public static void main (String args[]) {
ClasseTest objA;
objA=new ClasseTest(); // On peut aussi déclarer ClasseTest objA=new ClasseTest();
objA.initialise(1,3); /* ok: accès depuis l’extérieur (depuis une autre classe) à une
méthode public. Après appel de initialise(), x vaut 1 et y vaut 3 */
objA.y=3; // ne compile pas car accès depuis l’exterieur à un attribut privé: private y
}
}
El Mostafa DAOUDI- p. 49
El Mostafa DAOUDI- p. 50
25
VII. Méthodes d’accès aux valeurs des variables depuis l’extérieur
Comment peut on accéder à la valeur d’une variable protégée ??
Considérons la classe etudiant qui a les champs nom et prenom private.
Exemple:
class Etudiant {
private String nom, prenom;
public Etudiant(String st1, String st2){
nom=st1; prenom=st2;
}
}
public class MethodeStatic{
public static void main(String[] argv) {
Etudiant e= new Etudiant("Mohammed","Ali");
System.out.println("Nom = "+e.nom);
// ne compile pas car le champs nom est privé
/* comment faire pour afficher le nom de l’étudiant e; ??
}
}
El Mostafa DAOUDI- p. 51
Exemple:
class Etudiant {
private String nom, prenom;
public initialise(String nom, String Prenom){
this.nom=nom; this.prenom=prenom;
}
public String getNom (){
return nom;
}
public String getPrenom (){
return prenom
}
}
El Mostafa DAOUDI- p. 52
26
public class MethodeStatic{
public static void main(String[] argv) {
Etudiant e= new Etudiant("Mohammed","Ali");
e.initialise("Mohammed","Ali");
System.out.println("Nom = "+e.getNom());
System.out.println("Prenom = "+e.getPrenom());
}
}
El Mostafa DAOUDI- p. 53
El Mostafa DAOUDI- p. 54
27
Pour modifier la valeur de l’attribut nom (champs private), on définie
Un modificateur (mutateur) qui est une méthode permettant de
modifier le contenu d'une donnée membre protégée.
Exemple:
class Etudiant {
private int cne;
public void setCNE (int cne){
this.cne=cne;
}
}
public class MethodeStatic{
public static void main(String[] argv) {
Etudiant e= new Etudiant();
e.setCNT(23541654);
}
}
El Mostafa DAOUDI- p. 55
El Mostafa DAOUDI- p. 56
28
Exemple:
class Etudiant {
private String nom, prenom;
public initialise(String st1, String st2) {
nom = st1;
prenom = st2;
}
}
Comme les identificateurs st1 et st2 sont des arguments muets pour
la méthode initialise(), alors on peut les noter nom et prenom qui
n’ont aucune relation avec les champs private nom et prenom.
Dans ce cas la classe Etudiant peut s’écrire comme suit:
El Mostafa DAOUDI- p. 57
class Etudiant {
private String nom, prenom;
public initialise(String nom, String prenom){
this.nom=nom;
this.prenom=prenom;
}
}
El Mostafa DAOUDI- p. 58
29
IX. Champs et méthodes de classe
1. Champs de classe (variable de classe)
Considérons la définition simpliste suivante:
class ClasseTest {
int n;
double x;
}
Chaque objet de type ClasseTest possède ses propres valeurs (ses propres
données) pour les champs n et x.
Les valeurs des champs ne sont pas partagées entre les objets.
El Mostafa DAOUDI- p. 59
Les attributs qui peuvent être partagés entre tous les objets sont
nommés champs de classe ou variables de classe. Ils sont
comparables aux «variables globales ».
El Mostafa DAOUDI- p. 60
30
Exemple: Considérons la classe:
class ClasseTest {
static int n; // la valeur de n est partagée par toutes les instances
double y;
}
ClasseTest objA1=new ClasseTest(), objA2=new ClasseTest();
Ces déclarations créées deux objets (instances) différents: objA1 et objA2.
Puisque n est un attribut précédé du modificateur static , alors il est
partagé par tous les objets en particulier les objets objA1 et objA2
partagent la même variable n.
objA1.n et objA2.n désignent la même donnée.
La valeur de l’attribut n est indépendante de l’instance (l’objet).
Pour accéder au champs statique n, on utilise le nom de la classe
ClasseTest.n // champs (statique) de la classe ClasseTest
El Mostafa DAOUDI- p. 61
Exemple1:
class ClasseTest {
int n;
double y;
}
public class MethodeStatic{
public static void main(String[] argv) {
ClasseTest objA1=new ClasseTest();
31
Exemple2:
class ClasseTest {
static int n; // la valeur de n est partagée par toutes les instances
float y;
}
public class MethodeStatic{
public static void main(String[] argv) {
ClasseTest objA1=new ClasseTest();
objA1.n+=4; // objA1.n vaut 4;
// équivalent à ClasseTest.n=4;
ClasseTest objA2=new ClasseTest();
// objA2.n = ?
// objA2 vaut 4 car champs statique .
}
}
El Mostafa DAOUDI- p. 63
2. Méthodes de classe
Ce sont des méthodes qui ont un rôle indépendant d’un objet
spécifique. Elles exécutent une action indépendante d’une
instance particulière de la classe
El Mostafa DAOUDI- p. 64
32
Exemple:
class ClasseTest{
…
private static int n; // champs de classe
private float x; // champs usuel
public static void f() { // méthode de clase
/* ici (dans le corps de la méthode f(), on ne pas accéder
au champs x, champs usuel
Par contre on peut accéder au champs statique n.
*/
}
}
El Mostafa DAOUDI- p. 65
33
Variable locale final
Considérons une variable locale précédé par le mot clé final.
• Si la variable est d’un type primitif, sa valeur ne pourra pas
changer.
• Si la variable référence un objet, elle ne pourra pas référencer un
autre objet mais l’état de l’objet peut être modifié
Exemple:
final Etudiant e = new Etudiant("Mohammed", "Ali");
...
Constantes de classe
• Usage
– Ce sont des variables de classes déclarées avec le mot-clé final
– Ce sont des constantes liées à une classe
– Elles sont écrites en MAJUSCULES
– Pour y accéder, il faut utiliser non pas un identificateur d’objet
mais le nom de la classe
Exemple:
public class Galerie {
public static final int MASSE_MAX = 150;
}
if (maVoiture.getWeightLimite() <= Galerie.MASSE_MAX) {...}
El Mostafa DAOUDI- p. 68
34
Ch. III. Les constructeurs
I. Un exemple introductif
Considérons la classe point suivante: elle dispose des méthodes:
- initialise pour attribuer des valeurs aux coordonnées d’un
points
- déplace pour modifier les coordonnées d’un point
- affiche pour afficher les coordonnées d’un point
El Mostafa DAOUDI- p. 69
El Mostafa DAOUDI- p. 70
35
public class TstPoint{
public static void main (String args[]) {
Point pA=new Point(); // création de l’objet pA
pA.initialise(1,1); // initialisation de l’objet pA
pA.deplace(2,0);
Point pB=new Point(); // création de l’objet pB
pB.initialise(2,3); // initialisation de l’objet pB
pB.affiche();
}
}
El Mostafa DAOUDI- p. 71
Remarque:
La création et l’initialisation des attributs sont séparées:
- Tout d’abord on crée l’objet (l’instance).
- Ensuite, dans notre exemple, pour chaque instance on
appelle la méthode initialise() pour initialiser l’objet ainsi
créer.
On personnalise l’état de l’objet
- Si on n’appelle pas la méthode initialise, l’objet de type Point
ainsi créer ne sera pas initialisé.
Pas d’erreur à la compilation mais risque de problème
sémantique : toute manipulation de l’objet, utilisera les
valeurs de l’initialisation par défaut.
36
II. Définition de Constructeur
• Le constructeur est une méthode spécial qui peut contenir des
instructions à exécuter à la création des objets, en particulier :
l’initialisation des attributs.
La création et l’initialisation peuvent être unifiées
Quand une classe possède un constructeur, Java l’appel
automatiquement à toute création d’objet avant qu’il ne puisse
être utilisé.
• Chaque classe a un ou plusieurs constructeurs qui servent à
– créer les instances
– initialiser l’état de ces instances
• Règles de définition d’un constructeur : un constructeur:
– porte le même nom que la classe.
– n’a pas de type retour.
– peut disposer d’un nombre quelconque d’arguments
(éventuellement aucun).
El Mostafa DAOUDI- p. 73
El Mostafa DAOUDI- p. 74
37
public class TestPoint{
public static void main (String args[]) {
Point pA=new Point(1,1); // création et initialisation de l’objet pA
pA.deplace(2,0);
Point pB=new Point(2,3); // création et initialisation de l’objet pB
pB.affiche();
}
}
Remarque:
- Les instructions: Point pA=new Point(); et pA.initialise(1,1) ; sont
remplacées par: Point pA = new Point(1,1);
Attention: L’instruction:
Point pA = new Point();
ne convient plus car le constructeur a besoin de deux arguments
El Mostafa DAOUDI- p. 75
Un autre exemple
public class Etudiant {
private String nom, prenom; // Variables d’instance
private int codeNatEtudiant;
El Mostafa DAOUDI- p. 76
38
III. Quelques règles concernant les constructeurs
1. Aucun type, même void, ne doit figurer devant son nom.
2. Lorsque le code de la classe comporte un constructeur alors il doit
être appelé à chaque création.
3. Lorsque le code d’une classe ne comporte pas de constructeur, un
constructeur par défaut sera automatiquement ajouté par Java.
Dans ce cas on peut créer des objets de la classe ClasseTest par
l’instruction ClasseTest c = new ClasseTest();
//ok si ClasseTest n’a pas de constructeur.
4. Règle générale: Si pour une classe ClasseA donnée, l’instruction
ClasseA a=new ClasseA(); est acceptée
Cela signifie que:
- Soit la classe ClasseA ne possède pas de constructeur
- Soit la classe ClasseA possède un constructeur sans arguments.
El Mostafa DAOUDI- p. 77
El Mostafa DAOUDI- p. 78
39
IV. Initialisation des attributs
On distingues 3 types d’initialisation des attributs:
1. Initialisation par défaut: les champs d’un objet sont toujours
initialisés par défaut.
------------------------------------ |---------------------------------
Type de l’attribut ( champ) | Valeur par défaut
------------------------------------ |--------------------------------
boolean | false
char | caractère de code nul
int, byte, short, int long | 0
float, double | 0.f ou 0.
class | null
---------------------------------------------------------------------
El Mostafa DAOUDI- p. 79
El Mostafa DAOUDI- p. 80
40
D’une manière générale, la création d’un objet entraîne toujours,
par ordre chronologique, les opérations suivantes:
- L’initialisation par défaut de tous les champs de l’objet.
- L’initialisation explicite lors de la déclaration du champ.
- L’exécution des instructions du corps du constructeur.
El Mostafa DAOUDI- p. 81
Entraîne successivement:
1. initialisation implicite (par défaut) des champs n et p de l’objet objA à 0
2. initialisation explicite: On affecte au champ n la valeur 10 (la valeur
figurant dans sa déclaration).
3. exécution des instruction du constructeur: Le corps du constructeur n’est
exécuté qu’après l’initialisation par défaut et l’initialisation explicite.
El Mostafa DAOUDI- p. 82
41
class ClasseA {
public ClasseA() { // ici n =20, p =10 et np = 0
np=n*p;
n=5;
}
private int n=20, p=10;
private int np;
}
public class Init {
public static void main (String args[]) {
ClasseA objA=new ClasseA();
// ici objA.n =5, objA.p = 10, mais objA.np = 200
}
}
Après appel du constructeur on a: n=5 , p=10 , np = 200
El Mostafa DAOUDI- p. 83
class Etudiant {
private String nom, prenom; // Variables d’instance
private int codeNatEtudiant;
public Etudiant(String n, String p) { // Constructeur
nom = n;
prenom = p;
}
public Etudiant(String n, String p, int cne) {// Constructeur
nom = n;
prenom = p;
codeNatEtudiant = cne;
}
}
El Mostafa DAOUDI- p. 84
42
public class TestEtudiant {
public static void main (String[] args) {
Etudiant e1, e2;
e1 = new Etudiant("Mohammed", "Ali");
e2 = new Etudiant("Ouardi", " fatima", 22564321);
}
}
El Mostafa DAOUDI- p. 85
El Mostafa DAOUDI- p. 86
43
Exemple: La classe Etudiant peut être réécrite de la façon
suivante:
class Etudiant {
private String nom, prenom; // Variables d’instance
private int codeNatEtudiant;
public Etudiant(String n, String p) { // Constructeur
nom = n;
prenom = p;
}
public Etudiant(String n, String p, int cne) {// Constructeur
this( n,p); // appel au constructeur Etudiant(String,String);
codeNatEtudiant = cne;
}
}
El Mostafa DAOUDI- p. 87
El Mostafa DAOUDI- p. 88
44
La syntaxe de la déclaration :
type identificateur;
Où
- identificateur est une suite de caractères pour désigner les différentes
entités manipulés par un programme: variables, méthode, classe, objet, …
- type désigne le type de la variable déclarée
El Mostafa DAOUDI- p. 89
El Mostafa DAOUDI- p. 90
45
II. Style de programmation non standard
Conventions de nommage en Java: ne sont pas obligatoire, mais
fortement recommandées (c’est essentiel pour la lisibilité du
code et sa maintenance).
• Identificateur: pas d'emploi de $ (et de caractères non ASCII)
• Nom de classe :
– Si le nom de la classe est composé de plusieurs mots, ils
sont accolés (on ne les sépare pas avec le trait _ souligné).
– Commencez chaque mot par une majuscule
Exemple: HelloWorld, ClasseTest, MonPremierProgramme.
El Mostafa DAOUDI- p. 91
El Mostafa DAOUDI- p. 92
46
Les commentaires
• Sur une seule ligne : style C++
// Ceci un commentaire
int taux = 75; // taux de réussite
• Sur plusieurs lignes : style C
/* Première ligne du commentaire
suite du commentaire */
El Mostafa DAOUDI- p. 93
El Mostafa DAOUDI- p. 94
47
III. L’affectation
• L’opération d’affectation affecte ( assigne) une valeur à une
variable. Elle est réalisée au moyen de l’opérateur « = ».
la syntaxe : identificateur = valeur ;
Signifie prendre la valeur du coté droit et la copier du coté
gauche.
• identificateur : désigne une variable.
• valeur : est une constante, une variable ou une expression qui
retourne une valeur du même type que la variable référencée
par identificateur .
El Mostafa DAOUDI- p. 95
El Mostafa DAOUDI- p. 96
48
Cas des Objets
Soient objA est objB deux objets,
L’affectation objA=objB; signifie qu’on copie la référence de
objB dans objA.
1. Après affectation, les références objA et objB pointent vers
le même objet référencé par objB.
2. L’objet qui a été initialement référencé par objA existe
toujours, mais on n’a aucun contrôle sur lui (il reste
inaccessible).
El Mostafa DAOUDI- p. 97
Exemple:
class A {
public int i;
}
public class TestAffectation {
public static void main(String[] args) {
A a=new A(); A b=new A();
a.i=6; b.i=11;
a=b; // a et b contiennent la même référence, on a: a.i=11
a.i=20; // b.i = 20
b.i=13; // a.i = 13
}
a= new A() Instance Instance
a a
a a
a= b
Instance b Instance
b b b
b= new B()
El Mostafa DAOUDI- p. 98
49
IV. Types de données en Java
2 groupes de types de données sont manipulés par Java:
– types primitifs
– objets (instances de classe)
El Mostafa DAOUDI- p. 99
1. Types primitifs
• Booléen:
Boolean : prend deux valeurs true ou false
• Caractère (un seul caractère) :
char : codé sur 2 octet par le codage Unicode
• Nombres entiers :
byte: représenté sur 1 octet (8 bits),
short: représenté sur 2 octets (16 bits),
int : représenté sur 4 octets (32 bits),
long : représenté sur 8 octets (64 bits).
• Nombres à virgule flottante :
float : flottant (IEEE 754) 32-bit
double : flottant (IEEE 754) 64-bit
50
1.1. Type booléen
• Sert à représenter une valeur logique du type vrai/faux:
– Une variable de type booléen est déclaré par:
boolean b;
b prend une des deux valeurs true ou false
• C’est un véritable type:
– Il est retourné par les opérateurs de comparaison
– Il est attendu dans tous les tests
• ne peut pas être converti en entier
51
1.3. Nombres entiers
- Les valeurs min/max
– byte : codé sur sur 1 octet = 8 bits
– short : compris entre –32 768 et 32 767
– int : compris entre –2.147 483 648 et 2 147 483 647
– long : compris entre -923 372 036 854 775 808
et 923 372 036 854 775 807
52
Types des résultats des calculs
Avec des nombres entiers
• Tout calcul entre entiers donne un résultat de type int
• si au moins un des opérandes est de type long, alors le résultat est
de type long
Exemple:
byte b1 = (byte)20;
byte b2 = (byte)15;
byte b3 = b1 + b2;
Provoquera une erreur à la compilation car :
(b1 + b2) est de type int (codé sur 32 bits) alors que b3 est de type
byte (codé sur 8 bits seulement).
53
Constantes nombres
• Une constante réelle est par défaut elle est de type double.
• Pour spécifier un float, il faut la suffixée par « F » ou « f ».
• Conversion automatique (implicite) : seulement float double
Exemple:
.567e2 // 56,7 de type double
5.123E-2F // 0,05123 de type float
float x=2.5f //ok
double y = 2.5; //ok
54
3. Transtypage
• Java est un langage fortement typé
• Dans certains cas, il est nécessaire de forcer le programme à
changer le type d’une expression. On utilise pour cela le cast
(transtypage) :
(type-forcé) expression
Exemple:
int i=13; // i codé sur 32 bit; 13 constante , par défaut de type int
byte b=i; // Erreur: pas de conversion implicite int byte
Casts autorisés
• En Java, deux seuls cas sont autorisés pour les casts :
– entre types primitifs,
– entre classes mère/ancêtre et classes filles.
55
3.1. Casts entre types primitifs
Un cast entre types primitifs peut occasionner une perte de données sans
aucun avertissement ni message d'erreur.
// b vaut 13 car conversion de 32 bits vers 8 bit (On considère les 8 bits
de poids le plus faible). i est un entier « petit »
int i = 130;
b = (byte)i; // b = -126 ! Pourquoi ???
byte b=130; // Provoque une erreur "cannot convert from int to byte" car 130
est hors max/min. Dans ce cas le cast explicite est obligatoire. Mais attention
au perte d’information:
56
• Les casts de types « flottants » vers les types entiers tronquent les
nombres :
float x=1.99F;
int i = (int)x; /* i = 1, et pas 2. On fait une troncature et non un
arrondi. */
int x = 10, y = 3;
double z;
z=x/y; // donne z=3.0; car x/y donne 3
si on veut que z=3.3333.. et pas 3.0, on doit écrire:
z = (double)x / y; // cast de x suffit
57
3.2. Casts entre entiers et caractères
• Ils font correspondre un entier à un caractère qui a
comme code Unicode la valeur de l’entier
• La correspondance char → int, long s’obtient par
cast implicite
• Le code d’un char peut aller de 0 à 65 535 donc
char → short, byte nécessite un cast explicite (short
ne va que jusqu’à 32 767)
• Les entiers sont signés et pas les char donc long, int,
short ou byte → char nécessite un cast explicite
58
Exemple avec la surcharge des méthode
class Point {
private int x,y;
public void Point (int x, int y){ this.x=x; this.y=y; }
pubic void deplace (int dx, int dy) { x+=dx; y+=dy; }
pubic void deplace (int dx) { x+=dx; }
pubic void deplace (short dx) { x+=dx; }
}
public class Surcharge {
public static void main(String arg[]) {
Point a=new Point(1,2);
a.deplace(1,3); // appel deplace (int,int)
59
V. Principaux opérateurs
• affectation : =
• arithmétiques : + - * / %
• comparaisons : < <= > >= == !=
• booléens : && || ! ^
• opérations bit-à-bit (sur les entiers) :
& | ^ ~ << >> >>>
• opération et affectation simultanées :
+= -= *= /= %= &= |=
^= <<= >>= >>>=
• pré/post-incrémentation : ++
pré/post-décrémentation : --
• opérateur ternaire : ?:
• création tableau ou objet (allocation mémoire) :
new
• test de type des références : instanceof
60
Remarque : La portée ( zone de validité de la déclaration)
d'une variable va de sa déclaration jusqu'à la fin du bloc où
elle est déclarée. Elle est fixée par les accolades { }.
Exemple 2:
{
int x=12; // x est accessible
{
int q;
q=x+100; // x et q tous les deux sont accessibles
}
x=6;
// x est accessible
q=x+2;
// Erreur: q est hors de portée
}
El Mostafa DAOUDI- p. 121
61
Portée des objet : Considérons une classe nommée ClasseA et qui a
une méthode publique nommée f().
objetA
{ Attribut1
Attribut2
ClasseA objA=new ClasseA(); ….
} // fin de portée
objA.f(); // Erreur car la référence objA est hors portée.
Remarque:
- La référence ObjA disparaît à la fin de la portée,
- Par contre l’objet qui a été référencé par objA existe toujours,
mais on n’a aucun contrôle sur lui (il reste inaccessible).
Les objets n’ont pas la même durée de vie que les types primitifs.
62
Le ramasse-miettes (garbage collector) est une tâche qui
– travaille en arrière-plan
– libère la place occupée par les instances non référencées
– compacte la mémoire occupée
• Il intervient
– quand le système a besoin de mémoire
– ou, de temps en temps, avec une priorité faible
if (exprBool) {
instructions; // exécutées si exprBool retourne true
}
if (exprBool) {
instructions1 ; // exécutées si exprBool retourne true
}
else {
instructions2; // exécutées si exprBool retourne false
}
63
if (exprBool1) {
instructions ; // Exécutées si exprBool1 retourne true
}
else if (exprBool2) {
instruction;
// Exécutées si exprBool1 retourne false et exprBool2 retourne true.
}
else {
// ...
}
2. Expression conditionnelle
L’expression:
Est équivalente à:
if (expressionBooléenne) {
expression1;
}
else {
expression2;
}
El Mostafa DAOUDI- p. 128
64
Exemple:
int x, y;
if (x % 2 == 0)
y = x + 1;
else
y = x;
Est équivalent à
int x;
int y = (x % 2 == 0) ? x + 1 : x;
65
4. Boucles de répétitions
Deux types de boucles :
- Répétitions « tant que »
while (expressionBooléenne) {
instructions; // corps de de la boucle
}
- Répétition « faire tant que »: le cors de la boucle est exécuté au moins
une fois.
do {
instructions; // corps de de la boucle
} while (expressionBooléenne);
66
6. Interruptions des boucles
• Break : sortie de la boucle : sort de la boucle et continue
l’exécution des instructions se trouvant après la boucle.
• continue : passage à l'itération suivante: interrompe
l’itération encours et passe à l’itération suivante
• break et continue peuvent être suivis d’un nom d’étiquette
qui désigne une boucle englobant la boucle où elles se
trouvent (une étiquette ne peut se trouver que devant une
boucle)
Etiquette de boucles
etiq1: while (pasFini) { // etiq1: étiquette
...
for (int i=0; i < n; i++) {
...
if (t[i] < 0)
continue etiq1; // réexécuter à partir de etiq1
...
}
...
}
67
VIII. Entrées Sorties Standards
1. Affichage standard (Ecriture sur la sortie standard)
• L’affichage standard à l’écran est effectué à l’aide des méthodes
print() et println() de la classe PrintStream (la classe de l'objet
System.out).
print() ne fait pas retour à la ligne .
println() fait retour à la ligne suivante.
Exemple 1:
float z=1.732f;
System.out.print("z=");
System.out.println(z);
System.out.println(" et 2z= " + (2*z));
Affiche:
z=1.732
et 2z= 3.464
Exemple 2:
Soit « obj » est un objet, l'expression
System.out.println("résultat: " + obj) ;
est équivalente à l'expression:
System.out.println ("résultat: " + obj.toString());
68
2. Lecture (Saisi à partir du clavier: La classe Scanner:
Les méthodes de la classe Scanner les plus intéressantes sont
certainement :
• byte nextByte() : Lecture d’une valeur de type byte
• short nextShort() : Lecture d’une valeur de type short.
• int nextInt() : Lecture d’une valeur de type int.
• long nextLong() : Lecture d’une valeur de type long.
• float nextFloat() : Lecture d’une valeur de type float.
• double nextDouble() : Lecture d’une valeur de type double.
• String nextLine() : Lecture d’une chaine jusqu‘à une marque
de fin de ligne. La marque de fin de ligne
n'est pas incorporée à la chaîne produite.
Exemple:
import java.util.Scanner;
public class TestScanner {
public static void main(String[] args) {
Scanner entree = new Scanner(System.in);
System.out.print("nom et prénom? ");
String nom = entree.nextLine();
System.out.print("âge? ");
int age = entree.nextInt();
System.out.print("taille (en m)? ");
float taille = entree.nextFloat();
System.out.println("lu: "+nom+", "+age+" ans, "+taille+" m");
}
}
69
Chp. V. Les tableaux
I. Introduction
• En Java
– Les tableaux sont considérés comme des objets. Ils sont manipulés
par des références.
– les variables de type tableau contiennent des références aux tableaux.
– Les éléments du tableau peuvent être d’un type primitif ou d’un type
objet.
– Les tableaux sont créés par l’opérateur new: allocation dynamique
par new.
– vérification des bornes à l'utilisation.
– La taille du tableau est définie à l'exécution. Elle est fixée une fois
pour toute.
70
2. Création: avec l’opérateur new
- Création après la déclaration
- Déclaration et création.
int [] tab = new int[5];
71
Remarques:
- La taille peut être une variable.
int n=Clavier.lireInt( ); // saisir au clavier l’entier n.
int tab[ ]=new int [n];
- Après exécution, la taille ne pourra plus être modifiée.
- Par contre la référence tab peut changer. Elle peut par exemple référencer un
autre objet de taille différente : par affectation ou par new.
Exemple:
double [] tab1, tab2; // tab1 et tab2 deux tableaux de type double
tab1=new double [10]; // tab1.length retourne 10
tab2=new double [15]; // tab2.length retourne 15
tab1=new double [36]; /* tab1 référence (désigne) un nouveau tableau de taille
tab1.length = 36. */
tab1=tab2 ; /* tab1 et tab2 désignent le même tableau référencé par tab2.
tab1.length retourne 15 */
72
Exemple:
public class ExempleTableau {
public static void main(String[] args) {
// DECLARATION
double[] tab;
// CREATION d’un tableau de dimension 100
tab = new double[100];
// AFFECTATION DES ELEMENTS DU TABLEAU
for (int i=0; i<tab.length; i++)
tab[i] = 1.;
// AFFICHAGE
for (int i=0; i<tab.length; i++)
System.out.print(tab[i]+" ");
System.out.println();
}
}
73
III. Affectation de Tableaux
• Java permet de manipuler globalement les tableaux par affectation de
leurs références.
• l’affectation ne modifie que la référence. Elle permet le changement de
références.
74
Allocation et copie par appel de: Arrays.copyOf() ou Arrays.copyOfRange()
Exemple: Soit tab un tableau d’entier déjà crée et initialisé. Création et
initialisation du tableau t2 à partir du tableau tab
import java.util.Arrays;
int[] t2= Arrays.copyOf(tab, 10);
// 1. crée le tableau t2
// 2. affecte au tableau t2 les 10 premiers éléments du tableau tab.
….
75
VI. Tableaux d’objets
Les éléments d’un tableau peuvent être d’un type objet.
Exemple
Considérons l’exemple de la classe Etudiant.
Soit setCNE(int ) une méthode de la classe Etudiant.
etudiantSMI[0].setCNE(11225467);
/* génère une erreur, car pour le moment « etudiantSMI[0] » ne contient que
la référence vers un objet de type Etudiant. Avant d’utiliser l’objet «
etudiantSMI[0] » il faut le créer. */
76
Attention:
Pour les tableaux d’objets, la méthode equals() de la classe Arrays compare les références.
Exemple: Considérons la classe «Point» (voir TD).
public class TestTableauObjet {
public static void main(String[] args) {
Point p1[]=new Point[2]; // p1 est tableau de Point de taille 2
Point p2[]=new Point[2]; // p2 est tableau de Point de taille 2
Point p3[]=new Point[2]; // p3 est tableau de Point de taille 2
p1[0]=new Point(1,2); p1[1]=new Point(5,8); // initialisation
p2[0]=new Point(1,2); p2[1]=new Point(5,8); // initialisation
boolean b1=Arrays.equals(p1,p2); // retourne false
p3[0]= p1[0]; p3[1] =p1[1]
boolean b2=Arrays.equals(p1,p3); // retourne true
p1=p2;
boolean b3=Arrays.equals(p1,p2); // retourne true
}
}
El Mostafa DAOUDI- p. 153
77
VIII. Tableaux à deux dimensions
- Un tableau à deux dimensions, ou matrice, représente un rectangle composé
de lignes et de colonnes.
- Si tab est un tableau à deux dimensions, l’élément de la ligne i et de la
colonne j est désigné par tab[i][j].
• Déclaration
int[][] notes; // déclare un tableau à deux dimensions
Chaque élément du tableau contient une référence vers un tableau
• Création:
On utilise l’opération new de création de tableaux. Il faut donner au moins
la première dimension
Exemple:
notes = new int[30][3]; // créé un tableau de 30 étudiants, chacun a au
plus 3 notes
Nous pouvons considéré le tableau notes comme un rectangle avec 30
lignes et 3 colonnes. Par convention, la première dimension est celle des
lignes, et la deuxième, celle des colonnes. Les indices débutent à 0. Lors
de sa création, les éléments du tableau sont initialisés par défaut.
78
• Dimensions du tableau
Soit t un tableau a deux dimensions:
– t.length : donne la longueur de la première dimension, c’est-à-dire le nombre
de lignes du tableau t.
– t[i].length : donne la longueur de la ligne i de t, autrement dit, le nombre de
colonnes de cette ligne.
• Initialisation
- Comme pour les tableaux à une dimension, on peut faire l’initialisation d’une
matrice par énumération de ses composantes.
Exemple 1:
int [][] tab = { {1,2,3,4}, {5,6,8}, {9,10,11,12}};
/* créé une matrice à 3 lignes (un tableau à 3 composante). Chaque ligne
(chaque composante) est un tableau unidimensionnelle à un nombre variable de
composantes:
*/
int [] t = tab[1]; // crée le tableau t= {5,6,8}
tab[1][2] = 8;
El Mostafa DAOUDI- p. 157
Exemple 2:
int[][] t;
t = new int[2][];
int[] t0 = {0, 1};
t[0]= t0; // t[0] est un tableau
t[1] = new int[] {2, 3, 4, 5}; // Déclaration et initialisation
for (int i = 0; i < t.length; i++) {
for (int j = 0; j < t[i].length; j++) {
System.out.print(t[i][j] + " ");
}
System.out.println();
}
Affiche:
0 1
2 3 4 5
79
Exemple 3:
Possibilité de forme non rectangulaire :
float triangle[][];
int n;
// ...
triangle = new float[n][]; //créé un tableau à n lignes
for (int i=0; i<n; i++) {
triangle[i] = new float[i+1]; // la ligne i est de dimension i
}
Quelques (rares) fonctions à connaître sur les tableaux de tableaux :
Arrays.deepEquals(); // à explorer
Arrays.deepToString(); //à explorer
80
1. Syntaxe:
class <ClasseDerivee> extends <ClasseDeBase>
Interprétation:
Permet de définir un lien d'héritage entre deux classes:
- La classe <ClasseDeBase> est le nom de la classe de base. On l’appelle aussi
une classe mère, une classe parente ou une super-classe. Le mot clef extends
indique la classe mère.
- La classe <ClasseDerivee> est le nom de la classe dérivée. Elle hérite de la
classe <ClasseDeBase>. On l'appelle aussi une classe fille ou une sous-classe.
Remarques:
- On a seulement besoin du code compilé de la clase de base.
- Toutes les classe héritent de la classe Object. Par défaut, on ne met pas extends
Object dans la définition d’une classe. Exemple:
public class TestClasse { …} // équivalent à :
public class TestClasse extends Objet { …}
81
Exemple:
class ClasseDeBase { // classe mère
// Définition des attributs et des méthodes
}
class ClasseDerivee extends Classedebase{
// ClasseDerivee : Sous-classe directe de la classe ClasseDeBase
// Définition de nouveaux attributs et méthodes (propres à la classe ClasseDerivee)
// Adaptation des méthodes qui sont déjà définies dans la classe mère
// ClasseDerivee hérite des méthodes et attributs de la classe ClasseDeBase
}
class ClasseSousDerivee extends ClasseDerivee {
/* ClasseSousDerivee: Sous-classe directe de la classe ClasseDerivee et sous-classe
indirecte de la classe ClasseDeBase */
// Définition de nouveaux attributs et méthodes (propres à la classe ClasseSousDerivee)
// Adaptation des méthodes qui sont déjà définies dans les superclasses directes ou indirectes
// ClasseSousDerivee hérite des méthodes et attributs des superclasses.
}
82
Remarques1:
Quand on écrit la classe dérivée on doit seulement:
– écrire le code (variables ou méthodes) lié aux nouvelles
possibilités: offrir de nouveaux services.
– redéfinir certaines méthodes: enrichir les services rendus
par une classe.
Remarques2:
– Java, ne permet pas l’héritage multiple. Il permet l’héritage simple
uniquement: chaque classe a une et une seule classe mère dont elle
hérite les variables et les méthodes.
– C++ permet l’héritage multiple.
83
Exemple 1:
class ClasseDeBase{
public ClasseDeBase(int i) { // constructeur de la classe de base
System.out.println(" Classe de Base: " + i);
}
}
class ClasseDerivee1 extends ClasseDeBase {
public ClasseDerivee1(int i, int j) { // constructeur de la classe dérivée 1
super(i+j); // appel du constructeur ClasseDeBase
System.out.println(" Classe dérivée1: " + i+ " , "+j);
}
}
class ClasseDerivee2 extends ClasseDerivee1{
public ClasseDerivee2(int i) { // constructeur de la classe dérivée 2
super(i , i+300); // appel du constructeur ClasseDerivee1
System.out.println(" Classe dérivée2: " + i);
}
}
Sortie:
Classe de Base : 314
Classe dérivée1: 7 , 307
Classe dérivée2: 7
84
3. Les cas possibles pour la construction des classes dérivées
Exemple 1:
class ClasseDeBase{
public ClasseDeBase(arguments) { // Constructeur de la classe de
base
…
}
…
}
class ClasseDerivee extends ClasseDeBase {
// Pas de constructeur
….
}
On obtient une erreur de compilation. Un constructeur de la classe dérivée
doit être défini et doit appeler le constructeur de la classe de base.
Exemple 2:
class ClasseDeBase{
public ClasseDeBase(arguments1) { // constructeur de la classe de base
…
}
}
class ClasseDerivee extends ClasseDeBase {
public ClasseDerivee(arguments2) { // constructeur de la classe dérivée
/* Première instruction = Appel de super(arguments1)
C’est obligatoire sinon une erreur
*/
….
}
}
El Mostafa DAOUDI- p. 170
85
Exemple 3:
class ClasseDeBase{
public ClasseDeBase() { // constructeur sans paramètres de la classe de base
…
}
}
class ClasseDerivee extends ClasseDeBase {
public ClasseDerivee(arguments2) { // constructeur de la classe dérivée
// l’appel de super() n’est pas obligatoire.
/* si super() n’est pas explicitement appelé, alors le constructeur
sans paramètres de la classe de base qui sera appelé par défaut.
*/
….
}
}
Exemple 4:
class ClasseDeBase{
public ClasseDeBase(arguments1) { // constructeur de la classe de base
…
}
public ClasseDeBase() { // constructeur sans paramètres de la classe de base
…
}
}
class ClasseDerivee extends ClasseDeBase {
public ClasseDerivee(arguments2) { // constructeur de la classe dérivée
// l’appel de super(avec ou sans arguments) n’est pas obligatoire.
/* si super n’est pas explicitement appelé, alors le constructeur sans
paramètres de la classe de base qui sera appelé par défaut. */
….
}
}
El Mostafa DAOUDI- p. 172
86
Exemple 5:
class ClasseDeBase{
// Pas de constructeur
…
}
class ClasseDerivee extends ClasseDeBase {
public ClasseDerivee(arguments) {
/* appel implicite du constructeur par défaut de la
classe de base */
….
}
}
Exemple 6:
class ClasseDeBase{
// Pas de constructeur
…
}
class ClasseDerivee extends ClasseDeBase {
// Pas de constructeur
….
}
87
Exemple pratique:
class ClasseDeBase{
public ClasseDeBase(int i) {
System.out.println(" Classe de Base: " + i);
}
}
class ClasseDerivee1 extends ClasseDeBase {
public ClasseDerivee1() {
// 1ère instruction obligatoire = appel explicite de super()
super(4); // par exemple
System.out.println(" Classe dérivée1: ");
}
}
class ClasseDerivee2 extends ClasseDerivee1{
public ClasseDerivee2() {
// Appel explicite de super() n’est pas obligatoire
// Appel implicite du constructeur sans paramètres de ClasseDerivee1
System.out.println(" Classe dérivée2: " );
}
}
El Mostafa DAOUDI- p. 175
Sortie:
Classe de Base : 4
Classe dérivée1:
Classe dérivée2:
88
Résumé:
Si on n'appelle pas le constructeur de la superclasse, le
constructeur par défaut est utilisé si:
- aucun constructeur n’est défini
- au moins un constructeur sans paramètre est défini
sinon le compilateur déclare une erreur
Remarques
• Une classe déclarée final ne peut pas avoir de classes
filles.
• La redéfinition d'une méthode public ne peut être private
• Une méthode final ne peut pas être redéfinie
4. Notion de la Redéfinition
– on redéfinit une méthode quand une nouvelle méthode
a le même nom et la même signature qu’une méthode
héritée de la classe mère.
la redéfinition d'une méthode d'une classe consiste à
fournir dans une sousclasse une nouvelle
implémentation de la méthode. Cette nouvelle
implémentation masque alors complètement celle de
la superclasse
Attention: Ne pas confondre redéfinition et surcharge
des méthodes :
– on surcharge une méthode quand une nouvelle
méthode a le même nom, mais pas la même signature,
qu’une autre méthode de la même classe
89
class ClasseDeBase{
public f(arg) {
…
}
}
class ClasseDerivee1 extends ClasseDeBase {
public f(arg) { // la méthode f() est redéfinie dans ClasseDerivee1
…
}
}
class ClasseDerivee2 extends ClasseDeBase{
public f(arg){ // la méthode f() est redéfinie dans ClasseDerivee2
….
}
}
Visibilité
Lorsqu'un attribut ou une méthode ont été définis dans une
classe et sont redéfinis dans une classe dérivée (qui en
hérite) alors les éléments visibles dans la classe dérivée sont
ceux redéfinis dans cette classe. Les éléments de la classe
de base (héritée) sont alors masqués.
Règles
On peut avoir les mêmes méthodes dans des classes héritant
les unes des autres. Dans ce cas, c'est la classe la plus
dérivée de l'objet qui détermine la méthode à exécuter, sans
que le programmeur ait à faire des tests sur le type de l'objet
à traiter (voir exemple suivant).
90
Soit f() est une méthode définie dans
la classe A. On suppose les liens
A* d’héritage suivants:
- Les classes B et C héritent de A
- Les classes D et E héritent de B
B - La classe F hérite de C
C* *: signifie redéfinition de f().
Dans class A: la méthode f() de A
Dans classe B: la méthode f() de A
Dans classe D: la méthode f() de D
E Dans classe E: la méthode f() de A
D* F
Dans classe C: la méthode f() de C
Dans classe F: la méthode f() de C
91
Exemple:
class Point {
private int x,y;
public void afficher(){
System.out.println(" je suis en "+ x +" et " +y);
}
}
class PointCol extends Point {
public void afficher() { // redéfinition de la méthode afficher()
super.afficher(); // appel de la méthode afficher() de la classe de base
System.out.println (" et ma couleur est: "+ couleur);
}
private byte couleur;
}
El Mostafa DAOUDI- p. 183
Par exemple:
super.f() désigne la méthode f() définie dans la première classe
ancêtre de la classe D.
La recherche de la méthode f() commence dans la classe mère de D,
ensuite dans la classe mère de cette classe mère, et ainsi de suite,
jusqu’à trouver la définition d’une méthode f() qui sera alors
exécutée
92
Exemple:
class ClasseA {
public String nom="Mostafa";
public void f(){
System.out.println("Je suis dans la classe de base ClasseA");
}
}
class A extends ClasseA {
public String nom="Ali";
public void ff(){
System.out.println("Je suis dans la classe de base A");
}
}
class B extends A {
public String nom = "Mohammed";
public void g(){
super.f(); // désigne la méthode f() de la classe ancêtre: classe ClassA
System.out.println( "Et je suis aussi dans la class derivée B : "+nom+ " " +super.nom);
// super.nom désigne le champ nom de la classe mère : classe A.
}
}
93
5. Sous-type
Le type B est un sous-type de A si on peut affecter une expression de
type B dans une variable de type A.
Les type primitifs
- int est un sous type de float (int i; float x=i;)
- float est un sous type de double (float y; double z=y;)
- …
Les objets
Les sous-classes d’une classe A sont des sous types de A. Dans ce
cas on peut écrire:
A a = new B(…); // la variable a est de type A, alors que
// l’objet référencé par a est de type B.
A aa; B b=new B();
aa=b; // aa de type A, référence un objet de type B
Par contre on ne peut pas avoir:
A a=new A();
B b;
b=a; // erreur: on ne peut pas convertir du type A vers le type B
Définitions:
- La classe réelle (ou le type réel) de l’objet est la classe du
constructeur qui a créé l’objet
Exemple: Soit B une sous classe de A
A a = new B(…); // B est la classe (type) réelle de l’objet a
94
Cas des tableaux
Soit B une classe qui hérite de la classe A, alors on peut écrire :
A[] tab = new B[5];
Attention: Dans tab[] il faut des objets de la classe réelle et non celles
du type déclaré (c’est à dire des objets de type B et non de type A).
Par exemple, si on a les instructions suivantes:
A[] tab = new B[5]; // A est le type déclaré du tableau tab.
// les éléments de tab doivent être du type réel c’est des instances
// de la classe B et non de de la classe A.
A a = new A();
tab[0] = a; // on affecte à tab[0] une instance de type A
/* Passe à la compilation mais provoquera une erreur à l’exécution
car tab[0] reçoit une valeur de type A et non une valeur de type B. */
95
public class TestPolymorphisme {
public static void main(String [] args ) {
ClasseA a=new ClasseA();
ClasseB b = new ClasseB();
a.f(); // appelle la méthode définie dans ClasseA
a=b; // le type déclaré de a est ClasseA. Le type réel de a est ClasseB
a.f(); // appelle la méthode définie dans ClasseB
a.g(); // appelle la méthode définie dans ClasseA
b.g(); // appelle la méthode définie dans ClasseA
b.h(): // appelle la méthode h() définie dans ClasseB
}
}
Il faut noter que la même écriture a.f(); peut correspondre à des appels
différents de la méthode f(). Ceci est réalisé grâce au polymorphisme.
Soit f() une méthode non static redéfinie dans la classe « ClasseB ».
ClasseA objA = new ClasseB();
objA.f(); // Appel de f() redéfinie dans ClasseB (classe effective=classe
// réelle de l’objet), même si objA est une référence de type
// ClasseA (Classe déclarée de l’objet).
96
Attention c’est important:
Si on a:
B b = new B();
b.h(); // appelle la méthode h() définie dans B
A a=new B();
a.h(); /* erreur à la compilation même si la classe réelle
possède la méthode h(). En effet la classe déclarée
(classe A) ne possède pas la méthode h(). */
97
II. Mécanisme de la liaison retardée: cas des méthodes redéfinies
Soit ClasseB la classe réelle d’un objet objB (ClasseB est la classe du
constructeur qui a créé l’objet objB) et soit ClasseA la classe de
déclaration de l’objet objB (ClasseA objB = new ClasseB();). Si on a
l’instruction: objB.f();
quelle méthode f() sera appelée ?
1. Si la méthode f() n’est pas définie dans une classe ancêtre de la classe de
déclaration (la classe ClasseA) alors erreur de compilation.
2. Si non
– Si la méthode f() est redéfinie dans la classe ClasseB, alors c’est cette
méthode qui sera exécutée
– Sinon, la recherche de la méthode f() se poursuit dans la classe mère de
ClasseB, puis dans la classe mère de cette classe mère, et ainsi de suite,
jusqu’à trouver la définition d’une méthode f() qui sera alors exécutée.
La méthode appelée ne dépend que du type réel de l’objet et non du type déclaré.
- Soit B une classe qui hérite de la classe A, et soit f() une méthode définie dans
A et redéfinie dans B.
- Soit C une classe qui hérite de la classe B.
A a = new B();
a.f(); // La méthode f() appelée est celle définie dans B.
Maintenant si on:
A a = new C(); // ok car C hérite de B qui hérite de A
a.f();
Si la méthode f() est redéfinie dans C alors la méthode appelée est celle définie
dans C.
Si la méthode f() n’est redéfinie dans C alors c’est la méthode f() redéfinie dans B
qui est appelée.
98
III. Utilités du Polymorphisme:
Le polymorphisme permet d’éviter les codes qui comportent de
nombreux embranchements et tests.
Exemple
Considérons une classe ClasseA. Supposons que les classes ClasseB
et ClasseC héritent de la super classe ClasseA. Dans un tableau
hétérogène, on range des objets de type ClasseB et ClasseC. Ensuite
on affiche le contenu du tableau.
Exemple
class ClasseA {
public void f() {} // méthode vide
public void g() {} // méthode vide
}
class ClasseB extends ClasseA {
public void f() { // traitement propre à ClasseB
System.out.println("traitement dans Classe B ");
}
}
class ClasseC extends ClasseA{
public void g() { // traitement propre à ClasseC
System.out.println("traitement dans ClasseC ");
}
}
El Mostafa DAOUDI- p. 198
99
public class TestPolymorphisme {
public static void main(String[] args) {
ClasseA [] objA = new ClasseA[3]; // objA tableau d’objets
objA[0]=new ClasseB(); // création de l’objet objA[0]
objA[1]=new ClasseC(); // création de l’objet objA[1]
objA[2]=new ClasseC(); // création de l’objet objA[2]
// Pour chaque élément du tableau, faire le traitement correspondant
for (int i=0; i < objA.length; i++) {
if (objA[i] instanceof ClasseB)
objA[i].f();
else if (objA[i] instanceof ClasseC)
objA[i].g();
}
}}
El Mostafa DAOUDI- p. 199
100
L’exemple peut être réécrit de la manière suivante en
exploitant le polymorphisme
class ClasseA {
public void f() {} // méthode vide
}
class ClasseB extends ClasseA {
public void f() { // traitement propre à ClasseB
System.out.println("traitement dans ClasseB ");
}
}
class ClasseC extends ClasseA {
public void f() { // traitement propre à ClasseC
System.out.println(" traitement dans ClasseC");
}
}
101
Ch. VIII. La gestion des exceptions
I. Définition et principe
• Une exception est un mécanisme pour traiter les anomalies qui se
produisent pendant l'exécution.
Principe
• Principe fondamental = séparer la détection et le traitement des
anomalies :
- signaler tout problème dès sa détection.
- mais regrouper le traitement des problèmes ailleurs, en fonction de
leur type
• Plutôt que de compliquer le code du traitement normal, on traite les
conditions anormales à part
• Le traitement « normal » apparaît ainsi plus simple et plus lisible
102
public class Point {
private int x, y;
public Point(int x, int y) {
if ((x < 0) || (y < 0)) { // Détection de l’erreur (l’Exception)
System.out.println("Erreur de Construction"); /* traitement
en cas d’erreur (traitement de l’exception) */
System.exit(-1);
}
else {
this.x = x ; this.y = y; // traitement normal
}
}
}
Un 1er test
public class TestException {
public static void main(String[] argv) {
private int i=3;
// début du bloc susceptible de générer une exception
Point a = new Point(6,1);
Point b = new Point(3, 4);
// Fin du bloc susceptible de générer une exception
System.out.println (" Exécution bien passée i= "+i);
}
}
Sortie du programme:
Exécution bien passée i=3
103
Un 2ème test
public class TestException {
public static void main(String[] argv) {
private int i=3;
// début du bloc susceptible de générer une exception
Point a = new Point(6,1);
Point b = new Point(-2, 4);
// Fin du bloc susceptible de générer une exception
System.out.println (" Exécution bien passée i= "+i);
}
}
Sortie du programme:
Erreur de Construction
L’appel de Point(6,1) n’a pas généré d’exception, donc il a été exécuté
normalement.
Par contre l’appel de Point(-2,4) a généré une exception et a provoqué l’arrêt
du programme (appel de System.exit(-1);). Par conséquent l’instruction
System.out.printl() n’a pas été exécutée.
104
Pratiquement:
Le code dans lequel une exception peut se produire est mis dans un bloc try, c’est-à-
dire on délimite un ensemble d’instructions susceptibles de déclencher une exception
par des blocs try {…}
try {
/* Code dans lequel une exception peut se produire */
}
La gestion des exceptions est obtenue par des blocs catch, où un bloc catch est associé à
une exception donnée.
Attention: Le bloc catch doit être juste après le bloc try, sinon erreur de compilation.
catch ( Type1Exception e) { // de type Type1Exception qui hérite de Exception
/* code de la gestion des exceptions */
}
catch ( Type2Exception e) { // de type Type2Exception qui hérite de Exception
/* code de la gestion des exceptions */
}
…..
105
Un 1er Test
public class Test {
public static void main(String[] argv) {
try { // dans ce bloc une exception peut se produire
Point b = new Point(-2, 4);
Point a = new Point(6, 1);
}
catch (ErrConst e) { // Erreur de type ErrConst qui hérite de Exception
// dans ce bloc on traite les exceptions
System.out.println("Erreur de Construction");
System.exit(-1);
}
System.out.println(" Excution bien passée");
}
}
Sortie du programme:
Erreur de Construction
L’appel de Point(-2,4); génère une exception, donc un saut est effectué vers le bloc catch().
L’exécution du code du bloc catch() a provoqué l’arrêt du programme (appel de System.exit(-1);),
par conséquent l’appel de Point(6,1) et les instructions après le bloc try {} n’ont pas été exécutées.
Un 2ème Test
public class Test {
public static void main(String[] argv) {
try {
Point a = new Point(9, 5);
Point b = new Point(3, 7);
}
catch (ErrConst e) { // Erreur de type ErrConst qui hérite de Exception
System.out.println("Erreur de Construction");
System.exit(-1);
}
System.out.println(" Exécution bien passée");
}
}
Sortie du programme:
Exécution bien passée
Les appels de Point(9,5) et Point(3,7) n’ont pas généré d’exceptions donc le code
du bloc catch() { } n’a pas été exécuté par conséquent l’exécution est allée
au-delà du bloc try.
106
IV. Lancement (déclenchement) d’une exception
Une méthode déclare qu’elle peut générer une exception par le mot clé throws.
Ensuite la méthode lance une exception, en créant une nouvelle valeur (un
objet) d’exception en utilisant le mot clé throw
Exemple:
public Point (int x, int y) throws ErrConst {
// Déclare que le constructeur Point() peut générer une exception
if ((x <0) || (y<0)) throw new ErrConst();
// Détection de l’exception et Création d’une nouvelle valeur d’exception
this.x = x ; this.y = y; // traitement normal
}
« ErrConst » est une classe qui hérite de la classe « Exception ». Elle peut être définie de la
manière suivante:
class ErrConst extends Exception{
}
N.B. Est-ce que cette définition est juste ??
Si ça passe à la compilation, veut dire que la classe « Exception » n’admet aucun
constructeur ou elle admet au moins un constructeur sans paramètres.
107
Un Deuxième exemple complet:
Supposons maintenant que la classe Point possède une méthode déplace() et
que le point doit rester dans le plan positif. Dans ce cas, le constructeur Point()
et la méthode deplace() doivent déclencher une exception.
class Point {
private int x, y;
public Point(int x, int y) throws ErrConst { // déclare une excéption
if ((x < 0) || (y < 0)) throw new ErrConst(); // déclenche une exception
this.x = x ; this.y = y;
}
public void deplace(int dx, int dy) throws ErrDepl{
if ((x+dx < 0) || (y+dy < 0)) throw new ErrDepl();
x = x+dx ; y = y+dy;
}
}
108
V. Bloc finally
• c’est une instruction optionnelle qui est exécutée quelle que soit le
résultat du bloc try (c’est à dire qu’il ait déclenché ou non une exception)
• Il permet de spécifier du code dont l’exécution est garantie quoi qu’il
arrive.
try {
...
}
catch (…) {
...
}
finally {
...
}
Exemple:
public class TestFinally {
public static void main(String[] argv) {
try {
Point a = new Point(6, 1);
a = new Point(-2, 4);
}
catch (ErrConst e) { // Erreur de type ErrConst qui hérite de Exception
System.out.println("Erreur de Construction");
}
finally {
System.out.println("Fin du Programme");
}
}
}
Affichage:
Erreur de Construction
Fin du Programme
109
VI. Constructeurs des exceptions
La création d'exception personnalisée peut être réalisée en rajoutant des
constructeurs et des membres supplémentaires. Par convention, toutes les
exceptions doivent avoir au moins 2 constructeurs :
– un sans paramètre
– un autre dont le paramètre est une chaîne de caractères utilisée pour
décrire le problème
Méthode printStackTrace()
class Point {
private int x, y;
public Point(int x, int y) throws Exception {
if ((x < 0) || (y < 0)) throw new Exception();
this.x = x ; this.y = y;
}
}
110
public class ExceptionTestStack {
public static void main(String[] argv) {
try {
Point a = new Point(6, 1);
a = new Point(-2, 4);
}
catch (Exception e) { // Erreur de type Exception
System.out.println("Erreur de Construction");
e.printStackTrace();
System.exit(-1);
}
}
}
Sortie du Programme:
Erreur de Construction
ErrConst
at Point.<init>(ExceptionTestStack.java:5)
at ExceptionTestStack.main(ExceptionTestStack.java:14)
class Point {
private int x, y;
public Point(int x, int y) throws ErrConst {
if ((x < 0) || (y < 0)) throw new ErrConst();
this.x = x ; this.y = y;
}
}
111
public class ExceptionTestStack {
public static void main(String[] argv) {
try {
Point a = new Point(6, 1);
a = new Point(-2, 4);
}
catch (ErrConst e) { // Erreur de type ErrConst qui hérite de Exception
System.out.println("Erreur de Construction");
e.printStackTrace();
System.exit(-1);
}
}
}
Sortie du Programme:
Erreur de Construction
ErrConst
at Point.<init>(ExceptionTestStack.java:5)
at ExceptionTestStack.main(ExceptionTestStack.java:14)
El Mostafa DAOUDI- p. 223
Méthode getMessage().
class Point {
private int x, y;
public Point(int x, int y) throws Exception {
if ((x < 0) || (y < 0)) throw new Exception(" Erreur aux points x=" +x+" et y=" +y);
this.x = x ; this.y = y;
}
}
112
public class Test {
public static void main(String[] argv) {
try {
Point a = new Point(6, 1);
a = new Point(-2, 4);
}
catch (Exception e) {
System.out.println(e.getMessage());
System.exit(-1);
}
}
}
Sortie:
Erreur au point x= -2 et y=4
113
public class Test {
public static void main(String[] argv) {
try {
Point a = new Point(6, 1);
a = new Point(-2, 4);
}
catch (ErrConst e) {
System.out.println(e.getMessage());
System.exit(-1);
}
}
}
Sortie:
Erreur au point x= -2 et y=4
114
V. Les classes d’erreurs/exceptions
• La classe java.lang.Throwable (classe fille de Object) est
la superclasse de toutes les erreurs et exceptions rencontrées
dans le langage de programmation Java.
Throwable
Error
Exception
115
Quelques sous-classes de RuntimeException (Exceptions
non contrôlées par le compilateur)
116
Ch. IX Interfaces et classes abstraites Abstractions
et quelques classes utiles
I. Classes abstraites
Une classe abstraite est une classe déclarée avec le mot clé abstract.
Elle est non instanciable . Elle sert uniquement de classe mère.
Exemple:
abstract class ClasseA {
…
}
Dans une classe abstraite on peut trouver:
- des champs,
- des méthodes ,
- des méthodes abstraites.
117
Les règles
• On ne peut pas instancier une classe abstraite (on ne peut pas
créer une instance (un objet) d’une classe abstraite).
Soit «ClasseA» une classe abstraite.
- On peut créer une référence sur un objet de type «ClasseA».
- Mais on ne peut pas créer un objet de type «ClasseA».
ClasseA objA; // autorisé
ClasseA objA = new ClasseA(); // n’est pas autorisé.
118
Intérêt des classe abstraites:
II. Interfaces
• Une classe est purement abstraite si toutes ses méthodes sont abstraites.
• Une interface est une classe purement abstraite. Elle est déclarée avec le
mot clé interface, dont toutes les méthodes sont publiques.
Une interface est une liste de noms de méthodes publiques. Dans
l’interface on définit la signature des méthodes qui doivent être
implémentées dans les classes qui les implémentent.
Une interface est un modèle pour une classe
Exemple d’interfaces
public interface Figure {
public void dessineFigure();
public void deplaceFigure(int dx, int dy);
}
El Mostafa DAOUDI- p. 238
119
Règles
• Toutes les méthodes d’une interface sont abstraites.
• Une interface n’admet aucun attribut.
• Une interface peut posséder des constantes publics
public interface NomInterface {
public static final int CONST = 2;
}
• Les interfaces ne sont pas instanciables. Soit « I » une interface:
I obj; // Juste
I a = new I(); // Erreur
• Tout objet instance d’une classe qui implémente l’interface peut être
déclaré comme étant du type de cette interface. Supposons que la classe
« ClasseA » implémente l’interface « I ». Alors on peut avoir
I obj = new ClasseA();
• Les interfaces pourront se dériver
120
Implémente partiellement une interface
• Soit une interface «I» et une classe «ClasseA» qui
l’implémente :
public class ClasseA implements I { … }
• « ClasseA » peut ne pas implémenter toutes les méthodes
de «I». Dans ce cas «ClasseA» doit être déclarée
abstract (elle lui manque des implémentations).
• Les méthodes manquantes seront implémentées par les
classes filles de « ClasseA »
La classe object fournit plusieurs méthodes qui sont héritées par toutes les
classes.
– public boolean equals(Object obj)
– public String toString()
– public int hashCode()
– protected Object clone()
– public Class getClass()
121
Comparer deux objets
Les opérateurs == et !=
• Soient objA et objB deux objets, « objA==objB » retourne «true»
si les deux objets référencent la même chose.
• Attention: Les tests de comparaison (== et !=) entre objets ne
concernent que les références et non les attributs.
Exemple d’utilisation:
Considérons la classe Point et pA et pB deux instances de Point.
Point pA=new Point(5,8); Point pB = new Point(5,8);
• pA.equals(pB) renvoie «false» car pA et pB référencent deux objet différents
(appel de la méthode définie dans la classe Object).
• Si on définie la méthode « equals » dans la classe Point comme suit:
public boolean equals (Point p){
return ((this.x==p.x)&&(this.y==p.y));
}
Dans ce cas pA.equals(pB) renvoie « true » car pA et pB ont le même contenue (pA
et pB coincident).
122
Classe Object – méthode toString()
public String toString();
• Elle renvoie une description de l’objet sous la forme d’une chaîne de
caractères de la forme:
nomDeLaClasse@AdresseMémoireDel’Objet
Dans ce cas, si on a:
Point pA=new Point(10, 32);
Alors:
System.out.println(pA) ; System.out.println(pA.toString()) ;
// appel de la méthode toString() redéfinie dans la classe « Point »
affiche : abscisse = 10 et ordonnée = 32
123