Informatique / Programmation

Transcription

Informatique / Programmation
Java / Introduction
Caractéristiques principales
Informatique / Programmation
§ Orientation Objet
§ (C++) --
Complément
§ Sécurité intégrée
Programmation orientée objet avec Java
01 : Introduction / Éléments de base
§ Portabilité
§ Robustesse (typage fort, gestion de la mémoire, ...)
§ Richesse des librairies de classes (plate-forme Java)
§ Multitâche intégré au langage (Multithreading)
§ Bonne intégration des communications réseau (Sockets, RMI, …)
Jacques Bapst
§ Évolutivité (SDK 1.0, 1.1, 1.2, 1.3, 1.4, 5.0, 6.0, 7.0, 8.0, …)
[email protected]
§ Java ¹ JavaScript
§ C# est fortement inspiré de Java
EIA-FR / Jacques Bapst
Java / Introduction
Mode de déploiement [1]
§ Application
§ Le langage Java a été conçu au sein de l'entreprise Sun
Microsystems (par une équipe dirigée par James Gosling).
• Java est synonyme de "café" en argot américain
Complément
Complément
§ Initialement baptisé Oak (chêne), il a été officiellement lancé en
1995 sous le nom Java
§ Le langage a été popularisé par :
Sa portabilité (indépendance des plates-formes)
Le slogan "Write Once Run Anywhere"
Une syntaxe de base très proche de C/C++
Une orientation Web native
Des éléments de sécurité intégrés
La gratuité de son kit de développement (JDK )
Son adoption dans la formation (écoles, universités)
Son nom ?
EIA-FR / Jacques Bapst
3
Java / Introduction
Bref historique du langage Java
•
•
•
•
•
•
•
•
PR1_01
PR1_01
2
•
•
•
•
Se comporte comme une application native
Lancement par une ligne de commande (lanceur natif)
Nécessite la disponibilité d'une machine virtuelle Java (JVM, JRE)
Peut accéder (par défaut) aux ressources locales
(fichiers, réseau, périphériques, ...)
§ Applet
• Lancement intégré dans des pages HTML
• S'exécute à l'intérieur du navigateur (IE, Firefox, ...)
• Utilise la machine virtuelle Java du navigateur
(attention aux versions de la machine virtuelle )
• Ne peut pas accéder (par défaut) aux ressources locales
(notion de Sandbox) Þ Sécurité
• Pratiquement plus utilisé (remplacé par Flash, HTML5, …)
EIA-FR / Jacques Bapst
PR1_01
4
Java / Introduction
Java / Introduction
Premier programme Java
Modes de déploiement [2]
§ Applet
§ Un premier programme (très poli) enregistré dans
le fichier "Bonjour.java" :
Navigateur
Complément
Applet
Nom de la classe : il doit correspondre au
nom du fichier source (sans l'extension)
JVM
Page HTML
//------------------------------------------// Un premier programme Java
//-------------------------------------------
Machine cible
public class Bonjour {
§ Java Web Start
public static void main(String[] args) {
• Application déployée et mise à jour par le Web
• Mise en mémoire cache locale (lancement plus rapide)
• L'application peut être lancée depuis une page HTML
ou comme une application locale
• Technologie destinée à remplacer les Applets (mais assez peu utilisée)
EIA-FR / Jacques Bapst
PR1_01
System.out.println("Bonjour à tous !");
}
Point d'entrée du programme
}
5
EIA-FR / Jacques Bapst
Différences par rapport à C/C++
Complément
Compilation et Interprétation
Syntaxe simplifiée (élimination des redondances C/C++)
Tailles définies pour les types primitifs
Garbage Collector (ramasse-miettes)
Éléments supprimés :
•
•
•
•
•
•
•
•
•
Interprétation
Compilation
Java VM
Linux
Pré processeur / #define / #include / typedef
Fichiers header (.h)
Structures / Unions
Fonctions et variables globales
Héritage multiple
Pointeurs
Surcharge des opérateurs
Instruction goto
Certains transtypages (casting) automatiques
EIA-FR / Jacques Bapst
7
Java / Introduction
Java / Introduction
§
§
§
§
PR1_01
Source
Compilateur
Bytecode
Interpréteur
Java VM
Windows
P1.java
javac P1.java
P1.class
java P1
Java VM
...
On utilise un éditeur
pour créer et modifier
les fichiers sources
PR1_01
6
EIA-FR / Jacques Bapst
Dans un environnement de développement
intégré (IDE) les commandes sont disponibles
sous forme de menus et barres d'outils
Machines virtuelles
(JVM/JRE)
PR1_01
8
Java / Eléments de base
Java / Eléments de base
Commentaires
Identificateurs
§ Les identificateurs sont des noms symboliques permettant de
référencer les éléments des programmes Java (variables, fonctions, ...).
§ Trois formes de commentaires :
// …Texte…
§ Règles pour les identificateurs :
ü Commence dès // et se termine à la fin de la ligne
ü Sur une seule ligne
ü A utiliser de préférence pour les commentaires généraux
• Doivent commencer par une lettre ou un souligné
(ou, à éviter, un caractère monétaire)
• Suivi (éventuellement) d'un nombre quelconque de lettres, chiffres
ou soulignés (ou, à éviter, de caractères monétaires )
• Distinction entre les majuscules et les minuscules
/* …Texte… */
ü Le texte entre /* et */ est ignoré par le compilateur
ü Peuvent s'étendre sur plusieurs lignes
ü Ne peuvent pas être imbriqués
ü Peuvent être utiles pour inactiver (temporairement) une zone de code
(éviter de créer des identificateurs qui ne se distinguent que par la casse)
• Utilisent le jeu de caractères Unicode (16 bits)
• Selon les plates-formes, les caractères alphabétiques spéciaux
(par exemple les caractères accentués, les lettres grecques, … ) peuvent
encore poser des problèmes => A éviter
• Les mots réservés du langage sont exclus
(voir liste à la page suivante)
/** …Texte… */
ü Commentaire de documentation (comme /* … */ mais avec fonction spéciale)
ü Interprétés par l'utilitaire javadoc pour créer une documentation au format HTML
ü Peuvent contenir des balises de documentation (@author, @param, …)
ü Peuvent contenir des balises HTML (Tags)
EIA-FR / Jacques Bapst
PR1_01
9
EIA-FR / Jacques Bapst
11
PR1_01
12
Java / Eléments de base
Java / Eléments de base
Mots réservés (Keywords)
Exemples de commentaires
§ Mots réservés du langage Java (mots-clé) :
/**
* Somme : Calcule une somme
*
* @author Marc Duchemin
* @version 2.3 08.07.2014
*/
public class Somme {
/*--------------------------------------------------+
| Programme principal
|
+--------------------------------------------------*/
public static void main(String[] params) {
abstract
default
goto
do
boolean
synchronized
if
private
this
double
implements
protected
throw
break
else
import
public
throws
byte
enum
instanceof
return
transient
case
extends
int
short
true
catch
false
interface
static
try
char
final
long
strictfp
void
class
finally
native
super
volatile
float
new
switch
while
for
null
const
total = a + b;
3)
1)
continue
//--- Affichage du résultat de l'addition
System.out.println("Résultat = " + total);
1)
package
assert
//--- Initialisation des variables
int a
= 1;
int b
= 2;
int total;
// Totalisateur
4)
2)
2)
2)
1)
Mots réservés du langage mais non utilisés actuellement
Littéraux prédéfinis
3) Depuis la version 1.4 du JDK
4) Depuis la version 1.5 du JDK
2)
}
}
EIA-FR / Jacques Bapst
PR1_01
PR1_01
10
EIA-FR / Jacques Bapst
Java / Eléments de base
Java / Eléments de base
Représentation en mémoire
Notion de variable [1]
§ En informatique, la notion de variable est une notion
fondamentale (un concept essentiel).
§ De manière interne, la zone mémoire allouée à une variable est
identifiée par une adresse.
§ Une variable définit une case mémoire nommée et typée.
§ Cette adresse est complètement cachée au programmeur : l'accès
à la zone mémoire s'effectue en utilisant le nom de la variable.
• Le nom est représenté par un identificateur
• Le type définit le genre d'informations qui sera enregistré ainsi que
les opérations qui pourront être effectuées sur ces informations
• Il existe un certain nombre de types prédéfinis mais il est également
possible de créer ses propres types
Code Java
Variable Adresse Contenu
note
EIA-FR / Jacques Bapst
(à utiliser)
note
1216
1217
Type Identificateur ;
float
note;
Polygone triangle;
Notation abstraite
1215
. . .
float note;
. . .
§ Avant de pouvoir être utilisée, une variable doit préalablement être
déclarée (définition de l'identificateur et du type).
§ Syntaxe :
Représentation interne
Variable Adresse Contenu
note
PR1_01
1215
. . .
note = 5.2;
. . .
4.75
13
Java / Eléments de base
note
1216
note
5.2
5.2
1217
EIA-FR / Jacques Bapst
PR1_01
Java / Eléments de base
Notion de variable [2]
Types primitifs [1]
§ La valeur de la variable peut être définie (initialisée), consultée,
modifiée en utilisant le nom de la variable.
§ Les variables ont une visibilité et une durée de vie qui dépendent
du contexte dans lequel elles sont déclarées.
§ Le type d'une variable peut être soit un type primitif, soit un
type référence (c'est-à-dire le nom d'une classe ou d'un tableau)
§ Exemples :
Type
Contient
Taille
Valeurs
boolean
Booléen
[1 bit 1) ]
true, false
char
Caractère (entier non-signé)
16 bits
\u0000..\uFFFF
byte
Entier signé
8 bits
-128..127
short
Entier signé
16 bits
-215.. 215-1
int
unNombreEntier;
// Type primitif int
int
Entier signé
32 bits
-231.. 231-1
String
motDePasse;
// Classe String (prédéfinie)
Entier signé
64 bits
-263.. 263-1
Point
position;
// Classe Point
long
char[]
voyelles;
// Tableau de caractères
float
Nombre en virgule flottante
32 bits
±3.4*1038
// Tableau de Point(s)
double
Nombre en virgule flottante
64 bits
±1.7*10308
Point[] nuage;
1)
EIA-FR / Jacques Bapst
15
PR1_01
14
EIA-FR / Jacques Bapst
Dépend de l'implémentation de la machine virtuelle
PR1_01
16
Java / Eléments de base
Java / Eléments de base
Types primitifs [2]
Types primitifs [4]
§ Booléen (boolean)
§ Entiers signés (byte, short, int, long)
• Ne peuvent prendre que deux valeurs : Vrai ou Faux
• Ne peuvent pas être interprétés comme des valeurs numériques [0, 1]
• Valeurs littérales (valeurs qui figurent directement dans le code )
ü true
ü false
• Valeurs littérales (int par défaut) : notation habituelle
• Suffixe l ou L pour type long (L est préférable)
Vrai
Faux
(base 8)
• Préfixe 0b ou 0B pour valeur binaire
(base 2)
• Exemples :
0
123
-56
0377
433L
0b1011
0xff
0xA0B3L
Caractères Unicode (codage normalisé sur 16 bits)
Site de référence de la norme : www.unicode.org
Peuvent être traités comme des entiers (non-signés !)
Valeurs littérales
ü Entre apostrophes : 'A' (attention : "A" n'est pas de type char)
ü Séquence d'échappement pour certains caractères spéciaux
(voir tabelle page suivante)
EIA-FR / Jacques Bapst
PR1_01
17
Java / Eléments de base
Signification
\b
Retour en arrière (Backspace)
\t
Tabulateur horizontal
\n
Saut de ligne (Line-feed)
\f
Saut de page (Form-feed)
\r
Retour de chariot (Carriage-Return)
\"
Guillemet
\'
Apostrophe
\\
Barre oblique arrière (Backslash)
\xxx
Caractère Latin-1 (xxx : valeur octale 000..377)
\uxxxx
Caractère Unicode
(xxxx : valeur hexadécimale 0000..FFFF)
valeur de type int
valeur de type int
valeur de type int
377 [octal] = 255 [décimal]
valeur de type long
valeur binaire de type int
valeur hexadécimale de type int
valeur hexadécimale de type long
PR1_01
19
Java / Eléments de base
Types primitifs [5]
§ Nombres en virgule flottante (float, double)
§ Séquences d'échappement (char)
Code
//
//
//
//
//
//
//
//
EIA-FR / Jacques Bapst
Types primitifs [3]
EIA-FR / Jacques Bapst
Java 7
• Préfixe 0x ou 0X pour valeur hexadécimale (base 16)
§ Caractère (char)
•
•
•
•
• Préfixe 0 (zéro) pour valeur octale
• Norme IEEE 754-1985
• Précision
ü float
ü double
: env. 6 chiffres significatifs
: env. 15 chiffres significatifs
• Valeurs littérales (double par défaut) : notation habituelle (n.m)
• Suffixe f ou F pour type float
• Suffixe d ou D pour type double (rarement nécessaire )
• Notation exponentielle avec e ou E suivi de l'exposant
• Valeurs spéciales : infini, -infini, zéro négatif, NaN (Not a Number)
Attention :
PR1_01
18
EIA-FR / Jacques Bapst
Les nombres en virgule flottante sont des approximations de
nombres réels (tous les nombres réels ne peuvent pas être
représentés de manière exacte).
Il faut en tenir compte dans les comparaisons et notamment
dans les tests d'égalité (prendre en compte un "epsilon").
PR1_01
20
Java / Eléments de base
Java / Eléments de base
Types primitifs [6]
Conversions de types [1]
§ Mis à part le type booléen, tous les types primitifs peuvent être
convertis entre eux.
§ Nombres en virgule flottante (float, double)
123.45
17d
-4.032F
6.02e23
-5.076E-2f
//
//
//
//
//
valeur
valeur
valeur
6.02
-5.076
de type double (par défaut)
de type double
de type float
x 1023 de type double
x 10-2 de type float
§ L'encodage Unicode permet (si nécessaire) de considérer les
caractères comme des nombres.
Le type char peut donc agir comme un entier short mais il est non
signé (contrairement aux autres entiers).
§ Le caractère '_' peut être inséré dans les littéraux numériques
long
int
int
float
creditCardNr
tenMillions
bytePattern
pi
=
=
=
=
Java 7
1234_5678_9012_3456L;
10_000_000;
0b11000011_00001111_11110000_00110011;
3.14_15_93f;
// Infini
// Moins l'infini
// Not a Number (NaN)
(avec perte éventuelle de précision lors du passage en virgule flottante)
§ Conversion restrictive explicite (par transtypage / casting)
(sous la responsabilité du programmeur)
Remarque : Certaines conversions restrictives implicites sont automatiquement
effectuées lorsque le résultat d'une expression constante est assignée
à une variable (byte, short ou char) pour autant que la valeur de
l'expression puisse être représentée (sans perte) par la variable.
§ Cas particuliers (problèmes numériques) :
1.2/0.0
-5.1/0.0
0.0/0.0
§ Conversion élargissante / Promotion (automatique)
Double.POSITIVE_INFINITY
Double.NEGATIVE_INFINITY
short compteur = 12*34;
Double.NaN
EIA-FR / Jacques Bapst
PR1_01
21
EIA-FR / Jacques Bapst
Affichage sur la console
§ Conversions des types primitifs
Conversion vers
// Affichage (reste sur la même ligne)
// Affichage et retour à la ligne
§ Exemples :
Résultats
---------
Conversion de
int size = 123;
char unit = 'm';
System.out.print("Longueur : ");
System.out.print(size);
System.out.print(" ");
System.out.println(unit);
Longueur : 123 m
Même affichage mais en utilisant l'opérateur de concaténation (+)
int size = 123;
char unit = 'm';
System.out.println("Longueur : " + size + " " + unit);
EIA-FR / Jacques Bapst
23
Conversions de types [2]
§ Pour afficher une valeur littérale ou le contenu d’une variable sur la
console de sortie, on utilise les lignes de code suivantes :
System.out.println("Résultats");
System.out.println("---------");
PR1_01
Java / Eléments de base
Java / Eléments de base
• System.out.print(…);
• System.out.println(…);
// Conversion implicite int -> short
PR1_01
22
boolean
byte
short
char
int
long
float
double
boolean
–
N
N
N
N
N
N
N
byte
N
–
E
R
E
E
E
E
short
N
R
–
R
E
E
E
E
char
N
R
R
–
E
E
E
E
int
N
R
R
R
–
E
E*
E
long
N
R
R
R
R
–
E*
E*
float
N
R!
R!
R!
R!
R!
–
E
double
N
R!
R!
R!
R!
R!
R*
–
N : pas de conversion possible
R : conversion restrictive
E : conversion élargissante
(promotion)
* : perte de précision
EIA-FR / Jacques Bapst
! : valeur tronquée
PR1_01
24
Java / Eléments de base
Java / Eléments de base
Transtypage (Casting)
Chaînes de caractères
§ Les chaînes de caractères ne font pas partie des types primitifs
§ Conversion de type explicite (au risque du programmeur)
§ Les chaînes de caractères font partie des types référence
(ce sont des objets de la classe String)
§ Syntaxe : (Type_de_destination) Valeur_à_convertir
§ D'usage courant Þ Syntaxe particulière (simplifiée) pour les
valeurs littérales :
• Texte entre guillemets ("…")
§ Exemples :
int i = 17;
byte b = 4;
b = i;
b = (byte)i;
• Peuvent contenir des séquences d'échappement identiques
à celles définies pour les types char
• Ne peuvent pas s'étendre sur plusieurs lignes
// Conversion implicite : littéral int -> byte
// Erreur à la compilation
// Conversion explicite (int -> byte)
• Concaténation (mise bout à bout) avec l'opérateur "+"
• Conversions possibles : types primitifs ó String
float f = 23.86f;
i = (int)f;
// Valeur tronquée (i==23)
"Ceci est une chaîne de caractères"
"Le caractère \" se nomme 'guillemet'"
"La conca" + "ténation peut s'étendre " +
"sur plusieurs lignes"
EIA-FR / Jacques Bapst
PR1_01
25
Java / Eléments de base
EIA-FR / Jacques Bapst
PR1_01
Java / Eléments de base
Conversions types primitifs ó String
Types "Référence"
§ Il est possible de convertir des valeurs de types primitifs en chaînes
de caractères (String) et inversement en utilisant des fonctions
(méthodes) disponibles dans des classes appelées Wrappers.
§ En plus des huit types primitifs, Java définit deux autres catégories
de types de données :
- les classes et
- les tableaux
Conversions
qui seront étudiés en détail plus tard.
en String
de String
Type primitif
Wrapper
§ Les classes et les tableaux sont des types généralement
composites (représentant des valeurs multiples).
byte
Byte
toString(byte b)
parseByte(String s)
short
Short
toString(short s)
parseShort(String s)
§ Ils sont collectivement nommés : Types "Référence"
(on parle également parfois de types non-primitifs).
int
Integer
toString(int i)
parseInt(String s)
long
Long
toString(long l)
parseLong(String s)
§ Pour une variable de type référence, la case mémoire ne contient
pas directement les valeurs de la variable mais une référence
(une sorte de pointeur) vers une autre zone mémoire contenant les
valeurs.
float
Float
toString(float f)
parseFloat(String s)
double
Double
toString(double d)
parseDouble(String s)
String nom = "Dupont";
EIA-FR / Jacques Bapst
27
nom
D'autres fonctions de conversion sont également disponibles dans la classe String, notamment
la méthode valueOf() qui permet de convertir en String les valeurs de tous les types primitifs.
"Dupont"
PR1_01
26
EIA-FR / Jacques Bapst
PR1_01
28
Java / Eléments de base
Exemples de conversions
int
float
double
String
i;
f;
d;
s;
//
//
//
//
Variable
Variable
Variable
Variable
de
de
de
de
type
type
type
type
int
float
double
String
s = "412";
i = Integer.parseInt(s);
// Conversion String -> int
s = "1.234";
d = Double.parseDouble(s);
// Conversion String -> double
f = 123.8F;
s = Float.toString(f);
s = String.valueOf(f);
// Conversion float -> String
// Conversion float -> String
Attention : Ne pas confondre les littéraux de type caractère ou chaîne de caractères avec
les littéraux numériques. Par exemple '4', "4" et 4.
Le premier est un caractère (type char), le deuxième une chaîne de caractères
(type String) et le troisième est une valeur numérique entière (type int).
EIA-FR / Jacques Bapst
PR1_01
29
Java / Expressions et opérateurs
Expressions [2]
Informatique / Programmation
§ Les expressions complexes sont composées d'expressions
primaires (opérandes) et d'opérateurs (y c. invocation de méthodes)
§ Exemples :
total = 141
1 + 2
total = 7 + b
r = p.min(a, b)
Programmation orientée objet avec Java
02 : Expressions et opérateurs
Expression
Expression
Expression
Expression
d'affectation
avec opérateur d'addition
comprenant une addition et une affectation
comprenant une invocation de méthode
§ La valeur et le type d'une expression complexe sont déterminés
par les valeurs et types des opérandes ainsi que par les opérateurs
qui interviennent dans l'expression (les règles seront vues plus tard).
§ Certains opérateurs ont des effets de bord : ils changent par ex.
la valeur des opérandes et donc modifient l'état du programme
(affectation, incrémentation, décrémentation, invocation de méthodes,
création d'objets)
Jacques Bapst
[email protected]
a = 2
i++
EIA-FR / Jacques Bapst
Java / Expressions et opérateurs
PR1_02
Java / Expressions et opérateurs
Opérateurs
Expressions [1]
§ Les expressions sont des entités composées de littéraux, de
variables, d'invocations de méthodes et d'opérateurs. Ex : 4 + a / f(x)
§ Les expressions sont des éléments syntaxiques permettant de
déterminer une valeur à partir d'autres valeurs
§ Opérateurs unaires (monadiques)
-b
a++
§ Les expressions primaires : littéraux ou variables
a * b
y = z
(int)y
§ Exemples :
PR1_02
Résultat
1 opérande
2 opérandes
L'opérateur de multiplication est binaire
L'affectation est également binaire
Transtypage (casting)
§ Opérateurs ternaires
Littéral entier (type int, valeur 141)
Littéral booléen (type boolean, valeur true)
Variable (type selon déclaration de variable, valeur actuelle de total)
Op
Opérateur monadique moins
Opérateur monadique de post-incrémentation
§ Opérateurs binaires (dyadiques)
§ La valeur résultante de l'évaluation d'une expression primaire
est la valeur littérale ou la valeur enregistrée dans la variable.
Le type résultant est celui de la valeur littérale ou de la variable
EIA-FR / Jacques Bapst
§ Les opérateurs sont des éléments syntaxiques qui effectuent
certaines opérations en utilisant les valeurs de leurs opérandes
(paramètres de l'opération).
Opérandes
§ L'évaluation d'une expression détermine une valeur et
un type de retour
141
true
total
3
3 opérandes
• Un seul opérateur ternaire en Java
x > y ? x : y
2
EIA-FR / Jacques Bapst
Retourne la valeur maximale entre x et y
PR1_02
4
Java / Expressions et opérateurs
Java / Expressions et opérateurs
Précédence et Associativité
Liste des opérateurs [1]
P A Opérateur
15 G .
[]
( params )
++, -14 D ++, -+, ~
!
13 D new
( type )
12 G *, /, %
11 G +, +
10 G <<, >>, >>>
9 G <, <=
>, >=
instanceof
8 G ==
!=
==
!=
P : Précédence
Type(s) des opérandes
objet, membre
tableau, int
méthode, liste de paramètres
variable
variable
nombre
entier
booléen
classe, liste de paramètres
type, quelconque
nombre, nombre
nombre, nombre
chaîne de caract., quelconque
entier, entier
nombre, nombre
nombre, nombre
référence, type
primitif, primitif
primitif, primitif
référence, référence
référence, référence
Opération
accès au membre d'un objet
accès à l'élément d'un tableau
invocation (appel) de méthode
post-incrémentation, décrémentation
pré-incrémentation, décrémentation
plus monadique, moins monadique
complément binaire
NON logique
création (instanciation) d'objet
transtypage (conversion de type)
multiplication, division, modulo
addition, soustraction
concaténation
décalage à gauche, droite, non-signé
inférieur, inférieur ou égal
supérieur, supérieur ou égal
comparaision de types
égalité (valeurs égales)
non-égalité
égalité (référence au même objet)
non-égalité
§ Précédence
(voir colonne P dans la liste des opérateurs)
• Définit, en l'absence de parenthèses, quelles opérandes sont liés à
quels opérateurs
• Plus le degré de précédence est élevé et plus les opérandes sont liés
à l'opérateur considéré
• Les parenthèses permettent de spécifier explicitement les liens entre
les opérandes et les opérateurs
• Conseil : Sauf cas triviaux, toujours mettre des parenthèses dans
les expressions complexes afin d'éviter toute ambiguïté
d'interprétation
§ Associativité
• S'il y a plusieurs opérateurs de même précédence, l'associativité définit
l'ordre dans lequel les opérations seront exécutées
ü De la gauche vers la droite (G)
ü De la droite vers la gauche (D)
A : Associativité
EIA-FR / Jacques Bapst
PR1_02
5
Java / Expressions et opérateurs
EIA-FR / Jacques Bapst
P A Opérateur
7 G &
&
6 G ^
^
5 G |
|
4 G &&
3 G ||
2 D ? :
1 D =
*=, /=, %=,
+=, -=, <<=,
>>=, >>>=,
&=, ^=, |=
Type(s) des opérandes
entier, entier
booléen, booléen
entier, entier
booléen, booléen
entier, entier
booléen, booléen
booléen, booléen
booléen, booléen
booléen, quelconque, quelconque
variable, quelconque
variable, quelconque
§ Effectuent des opérations arithmétiques et retournent des
résultats numériques
Opération
ET binaire (bit à bit)
ET logique
OU exclusif binaire (bit à bit)
OU exclusif logique
OU binaire (bit à bit)
OU logique
ET logique conditionnel 1)
OU logique conditionnel 1)
opérateur conditionnel (ternaire)
affectation
affectation avec opération
§ Le type du résultat dépend du type des opérandes
§ Si nécessaire, une conversion élargissante (automatique) des
opérandes est effectuée avant l'opération
+
-
plus, moins monadique
+
-
addition, soustraction
++
--
pré/post incrémentation, pré/post décrémentation
*
/
%
multiplication, division, modulo (reste de la division entière)
-2.7
i++
--j - 2
a * x*x + 4.2
5.6/3
L'opérande de droite n'est évaluée que si c'est nécessaire
17 % 5
EIA-FR / Jacques Bapst
7
Opérateurs arithmétiques
A : Associativité
1)
PR1_02
Java / Expressions et opérateurs
Liste des opérateurs [2]
P : Précédence
(voir colonne A dans la liste des opérateurs)
PR1_02
6
( ne pas confondre avec 17 / 5 )
EIA-FR / Jacques Bapst
PR1_02
8
Java / Expressions et opérateurs
Java / Expressions et opérateurs
Ordre d'évaluation
Évaluation des opérations [1]
§ Pour mettre en évidence l'ordre d'évaluation des opérations d'une
expression, on peut placer des parenthèses en fonction de la
précédence et de l'associativité des opérateurs impliqués :
§ Si l'un des opérandes est un nombre en virgule flottante,
l'arithmétique décimale (arithmétique réelle) est utilisée
(calcul en virgule flottante)
1 + 3 * 4 - 2 - 5
Précédence
11
G
12
G
11
G
11
G
§ Si les deux opérandes sont des nombres entiers, l'arithmétique
entière est utilisée (important pour les divisions et pour le domaine
des valeurs possibles)
Associativité
( ( 1 + ( 3 * 4 ) ) - 2 ) - 5
§ Les caractères (char) sont traités comme des entiers short
(leur valeur Unicode est utilisée)
v = a - i++
1
D
11
G
14
D
v = ( a - ( i++ ) )
§ Après placement des parenthèses, les opérateurs ne devraient
avoir comme opérandes que des expressions entre parenthèses
ou éventuellement un symbole ou une valeur littérale unique (isolé).
§ Analyse non terminée :
u = (a * b) - (c * d) + f(e);
EIA-FR / Jacques Bapst
9
PR1_02
§ L'arithmétique entière est circulaire et ne produit jamais de
dépassement (une division par zéro lève cependant l'exception
ArithmeticException)
§ L'arithmétique décimale (en virgule flottante) peut produire des
valeurs spéciales (infini, -infini, zéro négatif, NaN) mais ne lève
jamais d'exceptions
EIA-FR / Jacques Bapst
Évaluation des opérations [2]
Ordre d'évaluation / Ordre des opérations
§ Dans des expressions plus complexes (et un peu tordues) il est
nécessaire de bien distinguer l'ordre d'évaluation des opérandes
(qui s'effectue de gauche à droite) et l'ordre des opérations (qui dépend
de la précédence et de l'associativité des opérateurs).
Complément
11
Java / Expressions et opérateurs
Java / Expressions et opérateurs
§ De telles expressions pièges sont à éviter (il faut impérativement
écrire le code de manière moins ambiguë).
int i = 10;
int i=2;
int i=1, j=2;
i = i + (i=5);
i = ++i + ++i * ++i;
i = i+++j;
§ Le résultat d'une expression entière est de type int1) sauf si
l'un des opérandes est de type long, auquel cas l'expression
est de type long (voir diagramme page suivante)
§ Le résultat d'une expression réelle (comprenant au moins un
opérande en virgule flottante) est de type float1) sauf si l'un des
opérandes est de type double, auquel cas l'expression est de
type double (voir diagramme page suivante)
1)
par conversion élargissante automatique (promotion) des opérandes
byte
short
float
b = 12;
s = 167;
f = 1.2f;
int
i = s - b;
double d = f * 2.5;
EIA-FR / Jacques Bapst
PR1_02
PR1_02
10
EIA-FR / Jacques Bapst
// Expression entière, s et b sont convertis en int
// avant l'opération
// Expression réelle, f est converti en double avant
// l'opération (car 2.5 est de type double)
PR1_02
12
Java / Expressions et opérateurs
Java / Expressions et opérateurs
Évaluation des expressions arithmétiques
Opérateurs et nombres en virgule flottante
§ Les nombres en virgule flottante (float et double) ne sont que des
approximations des nombres réels car ils sont codifiés ( en
base 2) avec un nombre limité de bits pour la mantisse et pour
l'exposant (voir par ex. www.binaryconvert.com ou babbage.cs.qc.edu/IEEE-754).
§ Pour chaque opérateur arithmétique, d'éventuelles conversions
préalables sont effectuées en fonction du type de ses opérandes :
N
N
Nb à virg.
?
Y
Y
long
N
Conversion év.
et calcul en
int
Y
double
?
§ Même à l'intérieur du domaine de valeurs prévu et avec un nombre
de décimales inférieur à la précision maximale, une grande quantité
de nombres réels ne peuvent pas être représentés exactement.
?
Conversion év.
et calcul en
long
Conversion év.
et calcul en
float
Arithmétique entière
Conversion év.
et calcul en
double
§ C'est pourquoi il faut être très prudent lors de l'utilisation des
opérateurs relationnels avec les nombres en virgule flottante et
tenir compte de ces problèmes d'arrondi.
float a=1.0f, b=0.1f, c=0.2f;
(a+(b+c)) != ((a+b)+c)
// !!! true !!!
(a+(b+c)) < ((a+b)+c)
// !!! true !!!
Arithmétique décimale
Exemple : 17 / 3 + 1.0
EIA-FR / Jacques Bapst
float d=2.0E7f;
d == (d+1)
PR1_02
13
Java / Expressions et opérateurs
// !!! true !!!
EIA-FR / Jacques Bapst
PR1_02
15
Java / Expressions et opérateurs
Opérateurs relationnels
Opérateurs logiques
§ Effectuent des opérations de comparaison et retournent des
résultats booléens
§ Effectuent des opérations logiques et retournent des résultats
booléens
==
!=
égalité, inégalité
!
NON logique
<
>
plus petit, plus grand
&
ET logique
<=
>=
plus petit ou égal, plus grand ou égal
&&
ET logique conditionnel
(le 2ème opérande n'est évalué que si le 1er est vrai)
i < 5
if (age >= 18) {...}
while (i<100) {...}
if (objet1 != objet2)
OU logique
||
OU logique conditionnel
(le 2ème opérande n'est évalué que si le 1er est faux)
{...}
// Comparaison des références
^
PR1_02
OU exclusif logique
if (!found)
Attention : pour les types références (objets et tableaux) les opérateurs
d'égalité et d'inégalité comparent les références et non les
valeurs référencées.
EIA-FR / Jacques Bapst
|
Ne pas confondre avec l'élévation à la puissance !
{...}
if (size>1.4 || age>12)
{...}
if (t!=null && t.length>=2 && t[1]!=4)
14
EIA-FR / Jacques Bapst
{...}
PR1_02
16
Java / Expressions et opérateurs
Java / Expressions et opérateurs
Opérateurs orientés bits
Affectation avec opérateur
§ Effectuent des opérations bit à bit et retournent des résultats
entiers (signés)
~
Inversion (complément à 1)
&
ET (bit à bit)
|
OU (bit à bit)
^
OU exclusif (bit à bit)
<<
Décalage à gauche (zéros ajoutés à droite)
>>
Décalage à droite signé (bit du signe ajouté à gauche)
>>>
Décalage à droite non-signé (zéros ajoutés à gauche)
byte b = ~12
10 & 7
10 | 7
10 ^ 7
10 << 2
10 >> 2
-10 >> 2
-10 >>>2
//
//
//
//
//
//
//
//
§ Combinaison de l'affectation avec un opérateur (arithmétique ou
orienté bits)
§ Le type de l'opérande de gauche (variable) doit être compatible
avec le type de l'expression de droite
var op= expr
Ne pas confondre avec l'élévation à la puissance !
~00001100
00001010 & 00000111
00001010 | 00000111
00001010 ^ 00000111
00001010
00001010
11110110
11110110
=>
=>
=>
=>
=>
=>
=>
=>
11110011
00000010
00001111
00001101
00101000
00000010
11111101
00111101
§ Opérateurs combinés :
(-13)
( 2)
( 15)
( 13)
( 40)
( 2)
( -3)
( 61)
EIA-FR / Jacques Bapst
PR1_02
var = var op ( expr )
+=
-=
*=
&=
<<=
|=
>>=
^=
>>>=
/=
i += 2;
// i = i + 2;
a *= z + 4;
// a = a * (z + 4);
flag |= mask;
// flag = flag | mask;
// set some bits according to a mask
%=
EIA-FR / Jacques Bapst
17
Java / Expressions et opérateurs
PR1_02
19
Java / Expressions et opérateurs
Affectation / Assignation
Opérateur instanceof
§ Permet de tester si une expression (de type référence) est
compatible (convertible) avec un type donné.
Sera vu plus en détail dans le cadre du polymorphisme
§ Enregistre dans l'opérande de gauche (variable) la valeur de
l'opérande de droite (valeur de l'expression)
§ Le type de la variable (opérande de gauche) doit être compatible
avec le type de l'expression de droite
(si nécessaire, conversion élargissante automatique)
§ Le type et valeur de retour d'une expression d'affectation correspondent
au type de la variable et, respectivement, à sa valeur après affectation
§ Attention : Ne pas confondre l'opérateur d'affectation (=)
avec celui d'égalité (==)
"prend pour valeur" et non pas "est égal à"
a = b + c;
// La variable a prend pour valeur le résultat de la somme (b+c)
a = b = c;
// Associativité à droite Þ a = (b = c)
t[i] = circle.center();
EIA-FR / Jacques Bapst
est équivalent à
PR1_02
18
§ Retourne true si l'opérande de gauche (qui doit être une
expression de type objet ou tableau) est une instance du type
spécifié par l'opérande de droite (qui doit être un type référence)
"Texte" instanceof String;
"Texte" instanceof Object;
null
instanceof String;
new int[] {1} instanceof Object
new int[] {1} instanceof byte[]
//
//
//
//
//
true
true
false
true
false tableau d'int Û tableau de byte
// Utile pour prévenir des erreurs de transtypage
if (forme instanceof Polygone) {
Polygone p1 = (Polygone)forme;
}
EIA-FR / Jacques Bapst
PR1_02
20
Java / Expressions et opérateurs
Opérateurs particuliers
§ Ces opérateurs particuliers sont parfois considérés comme des
éléments syntaxiques, parfois comme opérateurs :
• Accès à un membre d'un objet (.)
Complément
obj.x
obj.f()
• Accès à un élément d'un tableau ([])
t[2]
• Invocation de méthode (())
rectangle.move(x, y)
• Création d'un objet (new)
new Point(4.0, -2.5);
new ArrayList();
• Conversion de type / Transtypage (())
(float)position
(int)(a*1.414f)
(Circle)shape
EIA-FR / Jacques Bapst
PR1_02
21
Java / Instructions
Instructions [2]
Informatique / Programmation
§ Une instruction vide est constituée d'un simple point-virgule (;)
Une instruction vide ne fait rien, mais son expression syntaxique
peut parfois être utile.
§ Une instruction peut s'étendre sur plusieurs lignes du fichier source
Dans ce cas, les retours à la ligne doivent être placés entre les
éléments syntaxiques.
Programmation orientée objet avec Java
§ Plusieurs instructions peuvent être placées sur une même ligne du
fichier source.
Cette pratique est généralement à éviter et doit être réservée aux
cas où les instructions sont fortement corrélées et assez courtes.
03 : Instructions et contrôle de flux
§ Le point-virgule marque la fin d'une instruction (et non la fin d'une
ligne).
Jacques Bapst
[email protected]
screen.draw(x, y);
x += dx; y += dy;
EIA-FR / Jacques Bapst
Java / Instructions
3
Java / Instructions
Instructions [1]
Bloc d'instructions
§ Un bloc d'instructions (appelé également instruction composée)
est constitué d'un certain nombre d'instructions quelconques
placées entre accolades ( {...} ).
§ Une instruction définit une opération qui sera exécutée par la
machine virtuelle Java.
§ Par défaut, les instruction sont exécutées séquentiellement (les
unes après les autres), dans l'ordre dans lequel elles ont été
rédigées (ordre d'apparition dans le fichier source).
§ Un bloc d'instructions peut être utilisé pratiquement partout où une
instruction est requise par la syntaxe Java.
if (a<b)
{
t = b;
b = a;
a = t;
}
§ Cependant, certaines instructions de contrôle de flux permettent
de modifier l'ordre d'exécution d'une manière bien définie
(instructions exécutées conditionnellement, répétition d'instructions, etc.).
§ Les expressions avec effets de bord (affectation, incrémentation,
décrémentation et invocation de méthodes) peuvent être utilisées
comme instructions; elles sont alors suivies d'un point-virgule :
// Début du bloc d'instructions
// Fin du bloc d'instructions
§ Pour mettre en évidence la structure du code, on indente les
instructions à l'intérieur du bloc.
La forme suivante est fréquemment utilisée : if (a<b) {
j = 2;
count++;
( Notez bien l'indentation )
move(dx, dy);
EIA-FR / Jacques Bapst
PR1_03
}
PR1_03
2
EIA-FR / Jacques Bapst
t = b;
b = a;
a = t;
PR1_03
4
Java / Instructions
Java / Instructions
Représentation en mémoire
Déclaration de variables locales [1]
§ Une déclaration de variable locale définit (dans la mémoire vive)
une zone mémoire dont la taille et le codage dépend du type de la
variable.
§ Une déclaration de variable locale (souvent simplement appelée
variable) définit une zone mémoire en lui associant un nom
(identificateur) et un type.
La déclaration permet en outre de spécifier (optionnellement) la
valeur initiale de la variable.
§ Les détails d'implémentation ne sont pas importants (mais il faut
retenir le principe).
§ Syntaxe :
{
Type Identificateur [ = Expression ];
int price;
price = 3;
{
int cost=2*price;
}
§ Toutes les variables locales doivent être déclarées et initialisées
avant d'être utilisées.
§ En Java, les déclarations de variables peuvent être placées
n'importe où dans les blocs d'instructions.
PR1_03
Contenu
1215
price
1216
3
1217
cost
1218
6
1219
Représentation abstraite usuelle (notation à utiliser)
price
5
3
cost
6
EIA-FR / Jacques Bapst
PR1_03
7
Java / Instructions
Java / Instructions
Portée des variables
Déclaration de variables locales [2]
§ Une seule instruction de déclaration de variable permet de déclarer
et d'initialiser plusieurs variables, pour autant qu'elles soient toutes
du même type.
§ Lors de déclarations multiples, les noms des variables (avec leurs
éventuelles valeurs initiales) sont séparés par des virgules.
§ Les variables locales ne peuvent être utilisées que dans la
méthode ou le bloc d'instruction au sein duquel elles ont été
déclarées
§ On définit la portée (scope) ou portée lexicale d'une variable la
zone de code où la variable est accessible (cette zone va de sa
déclaration jusqu'à la fin du bloc dans lequel elle est déclarée).
§ A la fin de leurs portées lexicales, les variables ne sont plus
visibles et le système peut récupérer l'espace mémoire qui leur
était alloué
int counter;
Point p;
int number= 0;
// Déclaration et initialisation
String s = getName();
// Valeur connue à l'exécution seulement
int i, j, k;
// Déclarations multiples
int i=2, j=5, k;
// i et j sont initialisés, k ne l'est pas
EIA-FR / Jacques Bapst
Adresse
}
Conseil : Pour faciliter la lecture du code, groupez de préférence les
déclarations de variables au début des structures (méthodes,
blocs d'instructions )
EIA-FR / Jacques Bapst
Variable
PR1_03
public static void m() {
int i = 0;
while (i<10) {
double d = 1.2 * i;
System.out.println(d);
i++;
}
System.out.println(i);
}
6
EIA-FR / Jacques Bapst
//
//
//
//
//
//
//
i
i
i
i
i
i
i
d
d
d
PR1_03
8
Java / Instructions conditionnelles
Java / Instructions conditionnelles
La sélection
Instruction if ... else
§ On appelle sélection la possibilité de choisir d'exécuter une ou
plusieurs instructions en fonction de la situation (exprimée sous
la forme d'une condition) prévalant à l'instant considéré.
if ( expression_booléenne ) instruction_A else instruction_B
§ Une clause else peut (optionnellement) être mentionnée dans
l'instruction if
§ On trouve trois formes de réalisation en Java :
§ L'instruction qui suit la clause else est exécutée si l'expression
booléenne (la condition) est fausse
• L'instruction conditionnelle (if (cond) ...) qui permet
d'exécuter ou non un bloc d'instructions.
• L'instruction d'alternative (if (cond) ... else ...) qui
permet d'exécuter un bloc d'instructions ou, alternativement, un
autre bloc d'instructions
Instruction(s)
if (average >= 4)
System.out.println("Pass");
else {
System.out.println("Fail");
repeat = true;
}
• L'instruction sélective (switch (expr) case ...) qui permet
(dans sa variante habituelle) de choisir d'exécuter un parmi
plusieurs blocs d'instructions
EIA-FR / Jacques Bapst
PR1_03
9
Java / Instructions conditionnelles
EIA-FR / Jacques Bapst
Expression
booléenne
true
Instruction(s)
A
PR1_03
11
Emboîtement d'instructions if ... else
§ L'instruction if / else peut contenir dans chacune de ses deux
branches une autre instruction if / else qui peut elle-même
contenir une autre instruction …
if ( expression_booléenne ) instruction
§ On peut ainsi avoir plusieurs niveaux d'emboîtement formant une
logique plus ou moins complexe.
§ Exécution d'une instruction de manière conditionnelle
§ La condition est exprimée par une expression booléenne
§ En l'absence de blocs d'instructions ({…}), la clause else se
rapporte toujours au if précédent (sans else) le plus proche
(l'indentation ne change pas la logique du code !).
§ L'instruction est exécutée si la condition est vraie
if (age >= 18) status = "Adult";
Expression
booléenne
true
if (x >= 2)
if (x <= 20)
status = 1;
else
if (x <= 10)
status = 2;
else
status = 3;
Instruction(s)
false
if (x >= 2)
if (x <= 20)
status = 1;
else
if (x <= 10)
status = 2;
else
status = 3;
L'indentation est importante pour la lisibilité du code !
EIA-FR / Jacques Bapst
false
Java / Instructions conditionnelles
Instruction if
if ((age<16) || isStudent) {
canHaveAllocations = true;
amount = 400;
}
B
PR1_03
10
EIA-FR / Jacques Bapst
if (x >= 2) {
if (x <= 20)
status = 1;
}
else {
if (x < 0)
status = 0;
else
status = 2;
}
PR1_03
12
Java / Instructions conditionnelles
Java / Instructions conditionnelles
Imbrication if ... else if ... [1]
Instruction switch [1]
§ Lorsque l'on doit choisir une instruction (ou un bloc d'instructions)
parmi plusieurs (groupes d'instructions mutuellement exclusifs) il
faut imbriquer les clauses if else if sur plusieurs niveaux.
if (n==1) {
...
}
else {
if (n==2) {
...
}
else {
if (n==3) {
...
}
else {
if (n==4) {
...
}
else {
...
}
switch ( expression ) {
case const1 : suite_instructions_1
case const2 : suite_instructions_2
// Code executed if n is 1
...
default : suite_instructions_default
}
// Code executed if n is 2
§ Instruction de sélection multiple parmi une liste d'instructions
(indexées) et dont le point d'entrée est déterminé par la valeur
d'une expression (constante) de type byte, short, int, char
Java 7
d'un type énuméré (enum) ou String
// Code executed if n is 3
§ A partir du point d'entrée, l'exécution se poursuit ensuite dans
les instructions suivantes ( celles des autres clauses case) jusqu'à la
fin de l'instruction switch ou jusqu'à l'instruction break (ou
return) qui interrompt l'instruction switch
// Code executed if n is 4
// Code executed otherwise
EIA-FR / Jacques Bapst
PR1_03
13
Java / Instructions conditionnelles
EIA-FR / Jacques Bapst
Instruction switch [2]
§ Si le nombre d'alternatives est grande, l'indentation provoque un
décalage du code vers la droite qui peut devenir gênant.
n = ...
switch (n) {
case 1 :
Instruction;
Instruction;
...
case 5 :
case 6 :
Instruction;
Instruction;
...
case 8 :
Instruction;
Instruction;
...
default :
Instruction;
Instruction;
...
}
§ C'est pourquoi l'on préférera, dans ce cas, la disposition suivante :
(n==1) {
...
}
else if (n==2) {
...
}
else if (n==3) {
...
}
else {
...
}
// Code executed if n is 1
// Code executed if n is 2
// Code executed if n is 3
// Code executed otherwise
Remarque : Il ne s'agit pas d'une nouvelle syntaxe mais simplement d'une mise
en page plus lisible (sans cumul de l'indentation).
EIA-FR / Jacques Bapst
15
Java / Instructions conditionnelles
Imbrication if ... else if ... [2]
if
PR1_03
PR1_03
14
EIA-FR / Jacques Bapst
// Variable of type byte, short, int, char, enum or String
Java 7
// Start here if n is 1
// Start here if n is 5 or 6
// Start here if n is 8
Point d'entrée
A partir du point d'entrée,
toutes les instructions qui
suivent sont exécutées jusqu'à
la fin de l'instruction switch
ou jusqu'à l'instruction break
(ou autre instruction d'interruption
comme return, throw, …)
// Start here if n ¹ {1, 5, 6, 8}
PR1_03
16
Java / Instructions conditionnelles
Java / Instructions conditionnelles
Instruction switch [3]
Instruction switch [5]
§ Le mot clé default définit un point d'entrée qui est sélectionné si
la valeur de l'expression ne correspond à aucune valeur dans la
liste des clauses case. Le mot clé default est optionnel et est
généralement placé comme dernière clause (ce n'est pas imposé
par le langage mais fortement recommandé).
true
Case
a
Instruction(s)
A
break;
false
§ Plusieurs clauses case peuvent étiqueter la même suite
d'instructions (même point d'entrée pour plusieurs valeurs différentes).
true
Case
b
§ Les valeurs associées aux clauses case doivent être des valeurs
ou expressions constantes (évaluables par le compilateur).
Instruction(s)
B
break;
false
§ Toutes les valeurs des clauses case doivent être différentes.
L'instruction switch est une instruction de bas niveau qui peut être remplacée
par un enchaînement d'instructions if…else. Les instructions if…else offrent, en
outre, davantage de flexibilité (expressions de types quelconques, utilisation de
variables et d'expressions relationnelles et logiques dans les clauses de
sélection) et n'imposent pas l'utilisation quasi systématique d'instructions
d'interruption (break, return, …).
EIA-FR / Jacques Bapst
PR1_03
true
Case
z
Instruction(s)
Z
break;
false
17
EIA-FR / Jacques Bapst
PR1_03
19
Java / Instructions conditionnelles
Java / Instructions conditionnelles
Instruction switch [4]
Instruction switch [6]
int month, nbDays;
month = . . .
Case
a
true
Instruction(s)
switch (month) {
case 4 :
case 6 :
case 9 :
case 11 :
nbDays = 30; break;
A
false
Case
b
true
Instruction(s)
B
case 2 :
nbDays = 28; break;
false
// Années bissextiles non considérées
default :
nbDays = 31; break;
}
Case
z
true
Conseil :
Instruction(s)
Z
false
EIA-FR / Jacques Bapst
PR1_03
18
EIA-FR / Jacques Bapst
Sauf cas exceptionnels, placez systématiquement
une instruction break (ou return) à la fin de chaque
clause case car il est rare que l'on souhaite l'exécution
des instructions des clauses case qui suivent celles du
point d'entrée.
PR1_03
20
Java / Instructions conditionnelles
Java / Instructions itératives
Itérations / Boucles
Instruction switch [7]
§ On appelle boucle ou itération l'exécution multiple d'une ou de
plusieurs instructions en fonction de la situation (exprimée sous
la forme d'une condition) prévalant à l'instant considéré.
boolean positiveAnswer = false;
char
switch
case
case
case
case
case
case
answer
= readKeyboardChar();
(answer) {
'y' :
'Y' :
'j' :
'J' :
'o' :
'O' : positiveAnswer = true;
break;
§ On trouve trois formes de réalisation en Java :
• L'instruction while qui permet de répéter un nombre quelconque
de fois (0 ou plus) l'exécution d'une instruction ou d'un bloc
d'instructions. Le nombre de répétitions n'est pas forcément connu
au moment d'entrer dans la boucle.
• L'instruction do … while qui permet de répéter un nombre
quelconque de fois (1 ou plus) l'exécution d'une instruction ou d'un
bloc d'instructions. Le nombre de répétitions n'est pas forcément
connu au moment d'entrer dans la boucle.
• L'instruction for qui permet de répéter un nombre quelconque de
fois (0 ou plus) l'exécution d'une instruction ou d'un bloc
d'instructions. Le nombre de répétitions est généralement connu
au moment d'entrer dans la boucle ( mais ce n'est pas toujours le cas).
case 'n' :
case 'N' : positiveAnswer = false;
break;
default
: System.out.println("Caractère incorrect");
}
EIA-FR / Jacques Bapst
PR1_03
21
Java / Instructions conditionnelles
EIA-FR / Jacques Bapst
PR1_03
Java / Instructions itératives
Instruction switch [8]
Instruction while
String typeOfDay;
switch (dayOfWeek) {
case "Monday":
typeOfDay = "Start of work week";
Java 7
while ( expression_booléenne ) instruction
§ Instruction itérative
break;
case "Tuesday":
case "Wednesday":
case "Thursday":
typeOfDay = "Midweek";
break;
case "Friday":
typeOfDay = "End of work week";
break;
case "Saturday":
case "Sunday":
typeOfDay = "Weekend";
break;
default:
typeOfDay = "Invalid day of the week";
23
•
•
•
•
•
L'expression booléenne est évaluée
Si elle est vraie, l'instruction est exécutée
Puis l'expression booléenne est évaluée à nouveau
etc...
L'instruction while se termine si l'expression booléenne est fausse
§ L'instruction est exécutée 0, 1 ou n fois
// Affiche les nombres de 0 à 9
int count = 0;
while (count <= 9) {
System.out.println(count);
count++;
}
break;
}
Expression
booléenne
true
Instruction(s)
false
Attention : La comparaison prend en compte les minuscules/majuscules
EIA-FR / Jacques Bapst
PR1_03
22
EIA-FR / Jacques Bapst
PR1_03
24
Java / Instructions itératives
Java / Instructions itératives
Instruction do ... while
Instruction for [2]
§ En lieu et place d'instructions, l'initialisation peut contenir la
déclaration (et éventuellement l'initialisation ) d'une ou plusieurs
variables locales (mais toutes du même type) dont la portée est
limitée au corps de la boucle
do instruction while ( expression_booléenne );
§ Instruction itérative
•
•
•
•
•
•
Exécute l'instruction
Évalue l'expression booléenne
Si elle est vraie, l'instruction est exécutée à nouveau
Évalue à nouveau l'expression booléenne
etc...
L'instruction do se termine si l'expression booléenne est fausse
§ La conclusion est fréquemment constituée par une instruction de
mise à jour d'un compteur de boucle (incrémentation par exemple )
§ L'initialisation, l'expression booléenne et la conclusion sont
facultatives mais le point-virgule est obligatoire
(par défaut, l'expression booléenne est vraie )
§ L'instruction est exécutée 1 ou n fois
Initialisation
do {
display("Nombre positif : ");
number = keyboard.readNumber();
} while (number < 0);
Instruction(s)
Expression
booléenne
// Affiche les nombres de 0 à 9
for (int count=0; count<=9; count++) {
System.out.println(count);
}
true
Conclusion
Expression
booléenne
true
Instruction(s)
false
false
EIA-FR / Jacques Bapst
PR1_03
25
Java / Instructions itératives
EIA-FR / Jacques Bapst
27
Java / Instructions itératives
Imbrication de boucles [1]
Instruction for [1]
§ On peut placer n'importe quelle(s) instruction(s) à l'intérieur d'une
instruction d'itération while, do ou for, y compris une nouvelle
instruction d'itération.
for ( initialisation ; expression_booléenne ; conclusion ) instruction
§ Instruction itérative
§ Les instructions itératives peuvent donc être imbriquées.
§ Les expressions d'initialisation et de conclusion peuvent être
formées par zéro, une ou plusieurs instructions (expressions)
séparées par des virgules
§ Une telle construction est très fréquente.
§ A deux exceptions près1), l'instruction for est équivalente à la boucle
while suivante :
initialisation;
while ( expression_booléenne ) {
instruction;
conclusion;
}
for (int i=1; i<=5; i++) {
System.out.println("i> " + i);
for (int k=0; k<=2 ; k++) {
System.out.println("
PR1_03
26
k> " + k);
}
System.out.println("--------");
}
1) - S'il y a un continue, conclusion sera exécuté dans l'instruction for mais pas dans while
- Initialisation et conclusion ne peuvent pas être des instructions séparées par des virgules
dans la boucle while
EIA-FR / Jacques Bapst
PR1_03
EIA-FR / Jacques Bapst
i> 1
k> 0
k> 1
k> 2
-------i> 2
k> 0
k> 1
k> 2
-------i> 3
k> 0
k> 1
k> 2
-------i> 4
k> 0
k> 1
k> 2
-------i> 5
k> 0
k> 1
k> 2
--------
PR1_03
28
Java / Instructions de rupture
Java / Instructions itératives
Imbrication de boucles [2]
§ Autre exemple d'imbrication de boucles :
for (int i=0; i<3; i++) {
System.out.println("i> " + i);
int j = 2*i;
while (j>0) {
System.out.println(" j> " + j);
for (int k=6; k>0 ; k=k-2) {
System.out.println("
k> " + k);
}
j = j/2;
}
int m = 4-i;
do {
System.out.println(" m> " + m);
} while (--m > 0);
}
EIA-FR / Jacques Bapst
Instruction break
i> 0
m>
m>
m>
m>
i> 1
j>
break [ étiquette ] ;
4
3
2
1
2
k>
k>
k>
j> 1
k>
k>
k>
m> 3
m> 2
m> 1
i> 2
j> 4
k>
k>
k>
j> 2
k>
k>
k>
j> 1
k>
k>
k>
m> 2
m> 1
§ L'instruction break force l'interpréteur à passer immédiatement
à la fin de l'instruction englobante switch, while, do ou for
la plus interne
6
4
2
6
4
2
§ L'instruction break peut être suivie du nom d'une étiquette (label).
Dans ce cas, elle a pour effet de quitter immédiatement l'instruction
englobante (qui peut être quelconque dans ce cas) portant l'étiquette
correspondante
6
4
2
testBreak:
for (int i=1; i<=5; i++) {
for (int j=1; j<=5; j++) {
if (j == 3) break;
if (i == 4) break testBreak;
System.out.println("i*j=" + i*j);
}
}
6
4
2
6
4
2
PR1_03
29
EIA-FR / Jacques Bapst
PR1_03
31
Java / Instructions de rupture
Java / Instructions itératives
Instructions étiquetées
Instruction continue [1]
§ On peut donner un nom (étiquette, label) à une instruction en la
précédant d'un identificateur et d'un caractère deux points (':') :
continue [ étiquette ] ;
§ L'instruction continue force la boucle englobante la plus interne
à démarrer une nouvelle itération
nom : instruction ;
§ L'instruction continue ne peut être utilisée qu'au sein d'une
boucle while, do ou for
§ Les étiquettes ne sont utilisées qu'en relation avec les instructions
d'interruption break et continue (voir pages suivantes).
§ Avec une étiquette, l'instruction continue force la boucle
englobante identifiée par l'étiquette à démarrer une nouvelle
itération
§ En Java, les étiquettes ne peuvent pas être utilisées pour effectuer
un branchement direct (goto label).
§ Effets :
• Avec while et do : évalue l'expression booléenne et, si elle est
vraie, exécute une nouvelle fois le corps de la boucle
Remarque : même si goto est un mot réservé du langage, il n'est pas
utilisé actuellement.
EIA-FR / Jacques Bapst
// Termine la boucle interne
// Termine la boucle externe
PR1_03
• Avec for : effectue les instructions de conclusion puis évalue
l'expression booléenne et, si elle est vraie, exécute une nouvelle
fois le corps de la boucle
30
EIA-FR / Jacques Bapst
PR1_03
32
Java / Instructions de rupture
Java / Instructions
Instruction continue [2]
Instruction assert [1]
§ Un exemple d'utilisation de l'instruction continue :
if (i == 4) continue testContinue;
Complément
testContinue:
for (int i=1; i<=5; i++) {
for (int j=1; j<=5; j++) {
if (j == 3) continue;
assert Expression_Booléenne ;
assert Expression_Booléenne : Expression_Msg ;
// Prochaine itération
// de la boucle interne
// Prochaine itération
// de la boucle externe
System.out.println("i*j=" + i*j);
}
}
§ L'instruction assert permet d'insérer des assertions dans le code
source.
Les assertions sont des affirmations que le programmeur tient pour
vraies à l'endroit où elles sont placées et qui pourront être vérifiée
lors de l'exécution du code (outil de conception).
§ L'expression booléenne représente l'affirmation qui doit être vraie.
§ L'expression optionnelle passée comme deuxième argument
permettra de définir (par conversion en chaîne de caractères) le
message associé à l'exception en cas de violation de l'assertion
(c'est-à-dire dans le cas où l'expression booléenne est fausse).
§ La violation d'une assertion lève l'exception AssertionError.
EIA-FR / Jacques Bapst
PR1_03
EIA-FR / Jacques Bapst
33
Java / Instructions de rupture
35
Java / Instructions
Instruction return
Instruction assert [2]
§ Exemple :
§ L'instruction return termine l'exécution d'une méthode en
cours d'exécution et rend le contrôle à la méthode appelante
en retournant (restituant) éventuellement une valeur (expression)
qui doit être compatible avec le type de la méthode.
§ Si une méthode déclare un type de retour, l'instruction return
(avec une expression compatible) doit obligatoirement figurer dans
le corps de la méthode (dernière instruction exécutable).
public static double square(double x) {
return x * x;
}
Complément
return [ expression ] ;
EIA-FR / Jacques Bapst
PR1_03
if (i % 3 == 0) {
...
}
else if (i % 3 == 1) {
...
}
else {
assert i % 3 == 2 : i;
...
}
// L'expression booléenne est-elle toujours vraie ?
§ Des paramètres de la machine virtuelle (-ea / -da) permettent
d'enclencher ou de déclencher l'évaluation des assertions lors du
lancement d'une application (par défaut, elle ne sont pas évaluées).
PR1_03
34
EIA-FR / Jacques Bapst
PR1_03
36
Java / Instructions
Instruction synchronized
Complément
synchronized ( objet_ou_tableau ) { instructions }
§ L'instruction synchronized permet d'éviter que plusieurs threads
(exécutions parallèles) de l'application modifient simultanément un
même objet
§ L'objet (ou le tableau) de l'expression est protégé contre toute
modification simultanée durant l'exécution des instructions (qui
constituent la section critique)
§ Un verrou exclusif est pris sur l'objet ou le tableau spécifié avant
d'exécuter les instructions
int[] a;
...
synchronized(a) {
...
}
EIA-FR / Jacques Bapst
// Tableau accessible depuis plusieurs
// threads
// Opérations sur le tableau (par ex. tri)
PR1_03
37
Java / Méthodes
Une méthode c'est …
Informatique / Programmation
§ On peut dire, en quelques mots, qu'une méthode…
• c'est le regroupement d'une suite d'instructions auquel on
attribue un nom (identificateur)
• peut être invoquée (appelée) par une instruction (dans une
méthode appelante)
Programmation orientée objet avec Java
• permet la déclaration (optionnelle) de variables locales
• peut être optionnellement paramétrée au moyen d'une liste
d'arguments (paramètres)
04 : Méthodes
• peut optionnellement retourner une valeur (un résultat) à l'appelant
• peut être liée à l'existence d'un objet (méthode d'instance) ou à
l'existence d'une classe (méthode statique)
Jacques Bapst
[email protected]
• peut optionnellement générer une exception qui indique qu'un
événement exceptionnel s'est produit durant son exécution (par
exemple une erreur)
EIA-FR / Jacques Bapst
Java / Méthodes
3
Java / Méthodes
Pourquoi créer des méthodes
Méthodes [1]
§ La taille des problèmes à résoudre à l'aide d'un programme peut
être très complexe, d'où la nécessité de :
§ Une méthode est une séquence nommée d'instructions.
• Subdiviser les problèmes en sous-problèmes (plus simples) que
l'on traite indépendamment :
[ approche Top / Down ]
Æ Abstraction, modularisation, raffinements successifs Å
• Réutiliser des parties de code existantes (exemple : entrée/sorties,
fonctions mathématiques, graphiques, etc) :
[ approche Bottom / Up ]
Æ Rapidité de développement, efficacité, fiabilité Å
PR1_04
§ Ces instructions peuvent être exécutées en invoquant (appelant) la
méthode.
§ Lorsqu'une méthode est invoquée, elle peut recevoir un certain
nombre de valeurs appelées arguments (ou paramètres).
§ Une méthode peut facultativement retourner une valeur d'un
certain type (elle se comporte alors comme une expression complexe).
On utilise également le terme fonction pour désigner une méthode
qui retourne une valeur.
§ Une invocation de méthode est une expression (avec effet de bord)
qui peut être également utilisée en tant qu'instruction simple (sans
exploitation d'une éventuelle de valeur de retour).
§ Une méthode permet de regrouper, sous un nom, une suite
d'instructions exécutable à répétition.
EIA-FR / Jacques Bapst
PR1_04
§ Après l'exécution de la dernière instruction de la méthode, le
contrôle retourne à l'instruction qui a invoqué la méthode.
2
EIA-FR / Jacques Bapst
PR1_04
4
Java / Méthodes
Java / Méthodes
Méthodes [2]
Déclaration de méthode
§ Une méthode est caractérisée par sa signature (ou en-tête) qui
comprend :
En_tête_de_méthode { Corps_de_méthode }
• le nom de la méthode
• le type et le nom de chacun des paramètres formels (arguments)
§ L'en-tête de la méthode définit la signature de la méthode.
• le type de la valeur retournée par la méthode (ou sinon void)
§ Le corps de la méthode comprend les instructions qui seront
exécutées lors de l'invocation de la méthode.
• les types des exceptions que la méthode peut générer
• divers modificateurs de méthode qui fournissent des informations
supplémentaires sur certaines propriétés de la méthode
§ La signature d'une méthode définit tout ce qu'il est nécessaire
de savoir pour l'utiliser (pour l'utiliser à bon escient, une description
du comportement est naturellement indispensable).
Remarque : Contrairement à d'autres langages (Ada, C++, ...) qui
imposent ou permettent de placer dans des unités de
compilation séparées les spécifications (en-têtes) et
implémentations (corps), le langage Java groupe ces
deux éléments dans une unique structure.
§ La signature constitue une partie importante de la spécification
de la méthode appelée aussi API (Application Programming Interface)
EIA-FR / Jacques Bapst
PR1_04
5
Java / Méthodes
EIA-FR / Jacques Bapst
PR1_04
7
Java / Méthodes
Méthodes [3]
En-tête de méthode
§ La syntaxe pour déclarer l'en-tête de la méthode est la suivante :
Modificateurs
Type de retour de
la méthode
Nom de la
méthode
public static int max(int a, int b)
int r = a;
if (b > a) r = b;
return r;
Variable locale
}
Valeur de retour
(Expression)
Liste des
paramètres formels
{
[ modificateurs ] type nom ( liste_param ) [ throws exceptions ]
modificateurs : Un ou plusieurs mots-clés séparés par des espaces. Ils définissent
certaines propriétés de la méthode (visibilité, etc).
Optionnel
En-tête de
la méthode
[public, private, protected, final, static, native, abstract, synchronized]
(signature)
type : Définit le type de retour de la méthode (fonction).
Si la méthode ne retourne pas de valeur, le type doit être void (vide)
Corps de
la méthode
nom : Nom de la méthode
(même règles que pour les identificateurs).
...
int v = max(k, 3);
...
liste_param : Liste de paramètres formels séparés par des virgules.
Chaque paramètre est défini comme une variable locale (type nom).
La liste de paramètres peut être vide (les parenthèses demeurent).
Invocation (appel) de
la méthode avec les
paramètres effectifs
EIA-FR / Jacques Bapst
exceptions : Liste des types d'exceptions pouvant être générées par la méthode
(les exceptions sont séparées par des virgules).
Optionnel
PR1_04
6
EIA-FR / Jacques Bapst
PR1_04
8
Java / Méthodes
Java / Méthodes
Corps de méthode
Exemples de méthodes [2]
{ Instructions }
//----------------------------------------------// Returns the max value between v1 and v2
//----------------------------------------------public static int max(int v1, int v2) {
if (v1 > v2) return v1;
else
return v2;
}
§ Le corps de la méthode est constitué d'une séquence
d'instructions délimitées par des accolades.
§ Des variables locales peuvent être déclarées, leur portée sera
limitée au corps de la méthode (à partir de la déclaration).
§ Si la signature de la méthode déclare un type de retour (autre
que void), le corps de la méthode doit comprendre une
instruction return suivie d'une expression compatible avec
le type de retour déclaré dans la signature.
Cette expression définit la valeur de retour de la méthode (la
valeur restituée).
EIA-FR / Jacques Bapst
PR1_04
//----------------------------------------------// Method that calls other methods
//----------------------------------------------public static double fctA(double a, int b, int c) {
int temp = max(b, c);
return square(a) / temp;
}
9
Java / Méthodes
EIA-FR / Jacques Bapst
11
PR1_04
Java / Méthodes
Exemples de méthodes [1]
Méthode main
§ La méthode main() joue un rôle particulier.
//----------------------------------------------// Method without parameter
// Prints a separator line
//----------------------------------------------public static void separate() {
System.out.println("------------------------");
}
§ C'est le point d'entrée d'une application Java (ce n'est pas le cas
pour les applets qui doivent disposer des méthodes init() et start()).
§ Elle est invoquée par la machine virtuelle lors du lancement de
l'application. La méthode reçoit en argument un tableau de String
contenant les éventuelles valeurs des paramètres de lancement
(pour plus de détail consulter le slide intitulé Arguments sur la ligne de
commande du chapitre consacré aux Entrées/Sorties).
//----------------------------------------------// Returns the square of the parameter val
//----------------------------------------------public static double square(double val) {
return val * val;
}
EIA-FR / Jacques Bapst
§ Sa signature est imposée.
//----------------------------------------------// Main method (displays "Hello")
//----------------------------------------------public static void main(String[] args) {
System.out.println("Hello");
}
PR1_04
10
EIA-FR / Jacques Bapst
PR1_04
12
Java / Méthodes
Java / Méthodes
Utilité des méthodes
Invocation de méthode [1]
§ En Java, c'est pratiquement la seule construction permettant
d'exécuter des instructions.
§ L'invocation (l'appel) d'une méthode provoque l'exécution de ses
instructions.
§ Permet le découpage d'un problème en sous-problèmes plus
simples.
§ Pour invoquer une méthode, on utilise son nom suivi de zéro,
une ou plusieurs expressions séparées par des virgules et placées
entre parenthèses.
§ Améliore la lisibilité du code source (si le nom des méthodes est
bien choisi, leur invocation donnera déjà au lecteur du code des
informations précieuses sur le rôle de ces méthodes).
§ Les valeurs de ces expressions constituent les arguments (ou
paramètres effectifs) de la méthode. Ils doivent correspondre
en types (compatibilité) et en nombre à la liste définie dans la
signature de la méthode.
§ Favorise le principe d'abstraction et d'encapsulation :
l'utilisateur d'une méthode n'a pas à connaître tous les détails
de l'implémentation; seule la spécification est nécessaire
(notion de "boîte noire").
§ Syntaxe :
Remarque : Les expressions constituant les paramètres effectifs sont évaluées de
gauche à droite. C'est important dans des expressions du genre :
f(f(a, f(b, c)), f(d, e));
§ Permet la réutilisation des instructions (évite de dupliquer le code
avec tous les inconvénients que cela comporte).
EIA-FR / Jacques Bapst
PR1_04
Nom_de_la_méthode ( expr1, expr2, ... )
13
Java / Méthodes
EIA-FR / Jacques Bapst
PR1_04
15
Java / Méthodes
Emplacement des méthodes
Invocation de méthode [2]
§ En Java, toutes les méthodes doivent être déclarées au sein d'une
classe. Il n'y a pas de méthodes globales.
§ Contrairement à d'autres langages, Java n'autorise pas de créer
directement une méthode à l'intérieur d'une autre méthode. Il n'y a
pas d'imbrication de méthodes (à moins de créer une classe locale).
§ Dans l'ordre des lignes du code source, les méthodes peuvent être
invoquées (appelées) avant d'avoir été déclarées.
Il est ainsi possible à deux méthodes de s'appeler mutuellement.
. . . . .
§ Les méthodes définies sans type de retour (déclarées avec void)
sont invoquées à la manière d'une instruction simple (donc suivies
d'un point-virgule).
separate();
§ Les méthodes définies avec un type de retour sont généralement
invoquées dans des expressions (affectation, paramètre effectif de
méthode, …) mais peuvent également être invoquées comme des
instructions simples ( dans ce cas la valeur de retour n'est pas utilisée).
double
double
int
String
public static void f(int i) {
System.out.println("f(" + i + ")");
if (i>0) g(--i);
}
. . . . .
public static void g(int j) {
System.out.println("g(" + j + ")");
f(j);
}
// Les parenthèses sont obligatoires
PI = 3.1416;
area, radius = 1.5;
error;
f = "config.ini";
area = PI * square(radius);
error = readFile(f);
readFile(f);
// Invocation dans une expression
// Invocation dans une expression
// Invocation comme instruction simple
. . . . .
EIA-FR / Jacques Bapst
PR1_04
14
EIA-FR / Jacques Bapst
PR1_04
16
Java / Méthodes
Java / Méthodes
Séquencement
Passage de paramètres [2]
§ Lors de l'invocation de méthodes, une pile d'appels est constituée
de manière à pouvoir revenir au point d'invocation après l'exécution
de la méthode (chemin de retour).
public void p() {
…
q();
…
}
public void q() {
…
r();
…
}
public void r() {
…
…
…
}
§ La méthode agit donc sur des copies locales des valeurs des
expressions transmises en paramètres lors de l'invocation.
§ A la sortie de la méthode (après l'exécution de la dernière instruction),
les variables contenant les copies locales ne sont pas
réassignées en retour (pas de "Copy Out").
§ A chaque invocation de la méthode, de l'espace mémoire est
alloué pour enregistrer les valeurs des paramètres effectifs (ainsi
que pour les autres variables locales déclarées dans la méthode).
Cet espace mémoire est libéré à la sortie de la méthode.
p();
q();
§ Les variables contenant les copies locales des paramètres
effectifs ainsi que les variables locales déclarées dans la
méthode ne peuvent donc pas être utilisées en dehors du
corps de la méthode .
r();
EIA-FR / Jacques Bapst
PR1_04
17
EIA-FR / Jacques Bapst
Java / Méthodes
19
PR1_04
Java / Méthodes
Passage de paramètres [1]
Passage de paramètres [3]
§ Lors de la définition d'une méthode, on déclare une liste
(éventuellement vide) de paramètres formels qui peuvent être
considérés comme des variables locales dans le corps de la
méthode.
§ Illustration du mécanisme de passage de paramètres lors d'un appel
de fonction.
§ Dans l'exemple, le paramètre effectif (nb) est copié dans la variable
locale représentant le paramètre formel (i) de la méthode triple().
§ Lors de l'invocation d'une méthode, on doit transmettre, pour
chaque paramètre formel, une expression dont le type est
compatible avec celui qui est déclaré dans la signature de la
méthode. Ces expressions constituent les paramètres effectifs.
public static void main(String[] args) {
int nb = 4;
int r
§ Le passage des valeurs des paramètres peut s'assimiler à une
assignation entre les variables constituées par les paramètres
formels et les expressions qui représentent les paramètres effectifs.
§ Cette assignation a lieu à l'entrée de la méthode (avant l'exécution de
la première instruction).
Ce mécanisme est appelé "Passage par valeur" (ou également
mode "Copy In").
nb
4
r
= triple(nb);
12
System.out.println("> " + nb + ", " + r);
}
i = nb;
public static int triple(int i) {
return 3*i;
}
i
4
nb
4
i
4
nb
4
Console
> 4, 12
EIA-FR / Jacques Bapst
PR1_04
18
EIA-FR / Jacques Bapst
PR1_04
20
Java / Méthodes
Java / Méthodes
Passage de paramètres [4]
Surcharge de méthodes [2]
§ Le mécanisme qui a été vu pour le passage de paramètres de types
primitifs s'applique également si les paramètres passés sont de
types référence (des objets ou des tableaux).
§ La technique consistant à définir plusieurs méthodes avec le
même nom s'appelle la surcharge de méthode (Overloading).
§ Lors de l'invocation d'une méthode surchargée, c'est le compilateur
qui détermine (sur la base du profil des paramètres) la méthode qui doit
être appelée.
§ Dans ce cas, on aura donc une copie locale de la référence mais
pas des valeurs référencées (c'est efficace à l'exécution mais peut
induire des effets de bord dont il faut être conscient).
Conseil :
§ Le détail du passage de paramètres de type référence ainsi que les
implications que peut induire ce mode de transfert seront décrits
dans le chapitre suivant consacré aux tableaux.
§ Il est possible de définir des méthodes comportant un nombre
variable de paramètres. Comme cette syntaxe fait appel à des
tableaux, elle sera décrite à la fin du chapitre suivant.
EIA-FR / Jacques Bapst
PR1_04
Dans un contexte donné, plusieurs méthodes ne doivent porter
le même nom que si les opérations effectuées ont une forte
similitude sémantique.
Remarque : Contrairement à d'autres langages (Ada, C++, ...), Java ne
permet pas de surcharger les opérateurs (+, -, *, /, ==, …).
EIA-FR / Jacques Bapst
21
Java / Méthodes
23
Java / Méthodes
Surcharge de méthodes (Overloading)
Récursivité [1]
§ Le langage Java permet de définir plusieurs méthodes avec le
même nom pour autant que la liste des paramètres soit
différente.
§ Une méthode est dite récursive si elle s'invoque elle-même.
§ Deux listes de paramètres sont différentes si :
Complément
• le nombre de paramètres est différent ou alors
• la liste ordonnée des types des paramètres est différente
(Remarque : la deuxième règle est suffisante)
§ On remarquera que :
• le type de retour de la méthode n'entre pas en considération
• le nom des paramètres formels non plus
§ Exemples :
PR1_04
public static long factorial(long x) {
if (x<0) { ... };
// Error if x is negative
if (x==0) return 1;
else
return x * factorial(x-1);
}
§ On parle de récursivité indirecte si la méthode m1 en cours de
déclaration invoque une autre méthode m2 qui, elle, invoque m1
dans ses instructions (directement ou indirectement).
public static int triple(int i) {
return (i*3);
}
public static float triple(float f) {
return (f*3);
}
EIA-FR / Jacques Bapst
PR1_04
22
EIA-FR / Jacques Bapst
PR1_04
24
Java / Méthodes
Récursivité [2]
Complément
§ Les méthodes récursives doivent toujours contenir une instruction
d'arrêt (généralement sous la forme d'une instruction if (…) )
correspondant à un cas de base qui termine la récursivité (sous
peine d'épuiser les ressources du système, notamment la
mémoire).
§ L'algorithme doit d'autre part garantir (dans toutes les situations)
une convergence vers le cas de base (c'est-à-dire se rapprocher
de l'instruction d'arrêt de la récursivité).
§ Certains algorithmes se prêtent particulièrement bien à l'écriture
de code récursif (parcours d'arbres, de graphes, fonctions
mathématiques récurrentes, ...).
EIA-FR / Jacques Bapst
PR1_04
25
Java / Tableaux
Déclaration de tableaux [1]
Informatique / Programmation
Type_des_éléments [] Identificateur ;
§ Déclaration de la variable identifiant l'objet de type tableau.
§ La variable déclarée constitue une référence (sorte de pointeur vers
une adresse mémoire) qui permet d'accéder au tableau.
Programmation orientée objet avec Java
§ Le littéral null est une valeur particulière qui indique l'absence de
référence (ou la référence vers rien).
05 : Tableaux
§ La taille du tableau n'est pas définie lors de sa déclaration mais
seulement lors de sa création.
Jacques Bapst
[email protected]
int[]
intArray;
// Déclaration d'un tableau de valeurs primitives int
Point[]
constellation;
// Déclaration d'un tableau d'objets Point
byte[][] matrix;
// Déclaration d'un tableau de tableaux de byte
EIA-FR / Jacques Bapst
Java / Tableaux
3
Java / Tableaux
Tableaux
Déclaration de tableaux [2]
§ Un tableau est une séquence indexée d'éléments (valeurs)
de même type.
Type_des_éléments [] Identificateur = Initialisation ;
§ Une expression d'initialisation peut être ajoutée à la déclaration;
dans ce cas, le tableau est créé et la taille est déterminée par le
résultat de l'expression d'initialisation.
§ Il est caractérisé par sa taille (nombre d'éléments qu'il peut
contenir) et par le type de ses éléments.
§ Le type tableau est un type référence (comme les objets).
§ L'expression d'initialisation doit retourner un objet de type tableau
compatible avec le type de la variable que l'on déclare.
§ Les éléments d'un tableau peuvent être des valeurs de types
primitifs, des objets ou des tableaux.
§ L'initialisation peut consister en une expression de création de
tableau (avec l'opérateur new [voir pages suivantes] ).
§ Il faut bien faire la distinction entre les deux étapes :
- la déclaration du tableau ([]) qui crée une variable
(référence) représentant un objet de type tableau
- et la création du tableau (new) qui alloue l'espace
mémoire pour enregistrer les éléments du tableau
et initialise le contenu
EIA-FR / Jacques Bapst
PR1_05
§ Une syntaxe particulière permet de spécifier un littéral tableau
comme expression d'initialisation : {expr1, expr2, expr3, ...}
(cette syntaxe, sans new, n'est autorisée que lors de la déclaration)
tab
0
0
1
0
2
0
PR1_05
char[] vowels= {'a','e','i','o','u','y'};
2
EIA-FR / Jacques Bapst
PR1_05
4
Java / Tableaux
Java / Tableaux
Création de tableaux [1]
Utilisation des tableaux [1]
new Type_des_éléments [ Taille ]
§ Chaque élément d'un tableau est assimilé à une variable à
laquelle on peut accéder individuellement. Par exemple : t[k]++
§ La taille du tableau (nombre d'éléments) est déterminée par
l'expression entre crochets qui doit avoir une valeur entière positive
(ou zéro); la taille ne doit pas obligatoirement être connue à la
compilation.
§ Chaque élément est identifié par un indice entier compris
entre 0 et (n-1), n étant la taille du tableau
§ L'accès aux éléments d'un tableau s'effectue de la manière
suivante :
§ Une fois qu'un tableau est créé, sa taille ne peut plus varier.
§ Les éléments du tableau sont initialisés à leurs valeurs par défaut
(false pour les booléens, 0 pour tous les autres types primitifs,
null pour les objets et les tableaux).
Nom_tableau [ indice ]
§ L'opérateur new retourne une référence à l'objet tableau créé .
int[]
topTen = new int[10];
String[] text
= new String[50];
int[] tab;
tab
= new int[3];
tab[0] = 7;
tab[1] = 4;
tab[2] = tab[0] + tab[1];
// Tableau de 10 entiers (int)
// Déclaration et création simultanées
byte[][] matrix = new byte[25][80];
Point[]
// Déclaration d'un tableau d'entiers (int)
// Création du tableau avec 3 éléments
// Assignation du premier élément
// Assignation et accès aux éléments
constellation = new Point[astro.getDimension()];
EIA-FR / Jacques Bapst
PR1_05
5
Java / Tableaux
EIA-FR / Jacques Bapst
7
Java / Tableaux
Création de tableaux [2]
Utilisation des tableaux [2]
§ Le nombre d'éléments d'un tableau peut être obtenu à l'aide
de l'attribut length qui est prédéfini pour tous les objets de
type tableau (accessible en lecture uniquement).
new Type_des_éléments [] {élém1, élém2, ...}
§ Combinaison de la création d'un tableau avec l'initialisation de
ses éléments (qui doivent être compatibles avec le type déclaré).
Exemple :
§ La taille du tableau n'est pas spécifiée explicitement.
Elle est déterminée par le nombre d'éléments énumérés
entre les accolades (agrégat).
nbElements = tab.length;
§ Si, lors de l'accès à un élément d'un tableau, l'indice spécifié est
négatif ou supérieur à l'indice du dernier élément (length -1),
l'exception ArrayIndexOutOfBoundsException sera générée.
§ Cette notation permet de créer des tableaux anonymes (non
affectés à une variable) qui peuvent, par exemple, être passés
en paramètre lors de l'invocation d'une méthode.
§ L'expression qui détermine l'indice doit être de type byte, short,
char ou int (le type long n'est pas autorisé).
§ Le littéral null peut être utilisé pour représenter l'absence de
tableau (comme pour tout autre objet)
// Exemple de tableau anonyme passé à la méthode askQuestion
String answer= askQuestion("Continue?", new String[] {"Yes", "No"});
EIA-FR / Jacques Bapst
PR1_05
PR1_05
Exemple :
6
char[] word = null;
EIA-FR / Jacques Bapst
PR1_05
8
Java / Tableaux
Java / Tableaux
Tableaux multidimensionnels [1]
Tableaux multidimensionnels [2]
§ L'attribut length peut être consulté pour chacune des dimensions
§ Les tableaux peuvent avoir plusieurs dimensions. On parle alors de
tableaux multidimensionnels (attention à ne pas confondre nombre
de dimensions et taille du tableau).
char[][] crossword = new char[5][10];
int nbRows = crossword.length;
// nbRows=5
int nbCols = crossword[0].length;
// nbCols=10
§ Un tableau multidimensionnel est un tableau de tableaux (de
tableaux, de tableaux, ...).
§ Lors de la création d'un tableau multidimensionnel, il n'est
pas obligatoire de définir la taille de toutes les dimensions
§ Chaque paire de crochets ([]) représente une dimension (aussi
bien pour la déclaration, la création que l'accès aux éléments)
int[][] myArray = new int[2][3];
myArray
§ Par contre, si l'on définit les tailles, il faut le faire dans l'ordre,
de gauche à droite.
// Éléments initialisés à 0
0
1
2
0
0
0
// Ok, déclaration de la première dimension
float[][][] colorPalette = new float[10][][];
// Ok, déclaration des deux premières dimensions
float[][][] colorPalette = new float[10][20][];
0
1
EIA-FR / Jacques Bapst
(cependant, la première dimension doit obligatoirement être définie).
0
1
2
0
0
0
// Erreur à la compilation !
float[][][] colorPalette = new float[][20][];
PR1_05
9
Java / Tableaux
PR1_05
11
Java / Tableaux
Tableaux multidimensionnels [1]
Tableaux multidimensionnels [3]
§ Exemple d'utilisation
§ Pour les tableaux multidimensionnels, les valeurs littérales
(initialiseurs) sont constituées par l'emboîtement d'accolades
contenant les éléments de chacune des dimensions
(reflet de la structure : tableau de tableaux).
//--------------------------------------------------------// Multiplication table 0x0 ... 9x9
//--------------------------------------------------------int[][] multTable = new int[10][10];
// Éléments initialisés à 0
for (int i=0; i<multTable.length; i++) {
for (int j=0; j<multTable[i].length; j++) {
multTable[i][j] = i*j;
}
}
EIA-FR / Jacques Bapst
EIA-FR / Jacques Bapst
PR1_05
//---------------------------------------------------------// Tableau de 7 éléments dont chacun représente
// un tableau de 5 éléments
//---------------------------------------------------------int[][] multTable = { {0,
{0,
{0,
{0,
{0,
{0,
{0,
10
EIA-FR / Jacques Bapst
0, 0, 0,
1, 2, 3,
2, 4, 6,
3, 6, 9,
4, 8, 12,
5, 10, 15,
6, 12, 18,
0},
4},
8},
12},
16},
20},
24} };
PR1_05
12
Java / Tableaux
Java / Tableaux
Tableaux multidimensionnels [4]
Représentation en mémoire [1]
§ Les tableaux multidimensionnels étant des tableaux de tableaux,
ils ne doivent pas obligatoirement être rectangulaires (ou cubiques
ou ...).
//---------------------------------------------------------// Tableau de 7 éléments dont chacun représente
// un tableau de taille variable
// (tableau triangulaire)
//---------------------------------------------------------int[][] multTable = { {0},
{0,
{0,
{0,
{0,
{0,
{0,
§ Chaque variable est associée à l'adresse d'une case mémoire
§ Pour les types primitifs, la case mémoire contient la valeur
§ Pour les types référence, la case mémoire contient une référence
à la zone mémoire contenant l'objet ou le tableau
§ Les illustrations qui suivent sont schématiques et servent à mettre
en lumière le principe de fonctionnement
(l'implémentation réelle peut être sensiblement différente)
Variable de type primitif
1},
2, 4},
3, 6, 9},
4, 8, 12, 16},
5, 10, 15, 20, 25},
6, 12, 18, 24, 30, 36} };
Variable
Adresse
Notation abstraite
Contenu
1215
1216
int number = 122;
number
1217
number
122
122
1218
1219
EIA-FR / Jacques Bapst
PR1_05
13
Java / Tableaux
EIA-FR / Jacques Bapst
15
Java / Tableaux
Tableaux multidimensionnels [5]
Notation abstraite [1]
§ Les éléments tableaux des tableaux multidimensionnels peuvent
être définis dynamiquement y compris leur taille si elle n'a pas été
déterminée lors de la déclaration.
//----------------------------------------------------------// Tableau de 100 éléments représentant chacun un
// tableau de taille variable (créé dynamiquement).
// Chaque élément du tableau est une chaîne de caractères.
//-----------------------------------------------------------
for (int i=0; i<s.length; i++) {
s[i] = new String[(i%16)+1]; // Création dynamique du sous-tableau
for (int j=0; j<s[i].length; j++) {
s[i][j] = i + "/" + j;
}
}
PR1_05
Déclaration de tableau
int[] array;
array
array= null;
array
/
La valeur null représente une
référence vers rien
Création de tableau
String[][] s = new String[100][];
EIA-FR / Jacques Bapst
PR1_05
array= new int[4];
array
0
1
2
3
0
0
0
0
Initialisation automatique des
éléments à leurs valeurs par défaut
14
EIA-FR / Jacques Bapst
PR1_05
16
Java / Tableaux
Java / Tableaux
Notation abstraite [2]
Notation abstraite [3]
Affectation des éléments du tableau
array[0]
array[1]
array[2]
array[3]
=
=
=
=
8;
17;
5;
1;
array
Tableaux multidimensionnels
0
1
2
3
8
17
5
1
char[][] grid = { {'a', 'b'},
{'o', 'i'},
{'x', 'y', 'z'} };
Déclaration et affectation combinées
grid
word
0
1
2
3
'M'
'a'
'r'
'c'
0
1
2
'Z'
'u'
't'
EIA-FR / Jacques Bapst
'b'
1
0
1
'o'
'i'
0
1
2
'x'
'y'
'z'
Par extension, le même mécanisme
s'applique aux tableaux comportant
plus de deux dimensions
PR1_05
17
Java / Tableaux
EIA-FR / Jacques Bapst
PR1_05
19
Java / Tableaux
Notation abstraite [3]
Référence / Objet référencé [1]
Affectation de tableaux
§ Une référence peut être assimilée à un pointeur vers une
adresse en mémoire (mais Java ne connaît pas de réels pointeurs).
name = word;
0
1
2
3
'M'
'a'
'r'
'c'
0
1
2
'Z'
'u'
't'
Cette zone mémoire n'est plus
référencée. Elle peut être effacée
par le ramasse-miettes
(Garbage Collector)
System.out.println(name[1]);
word[1] = 'o';
System.out.println(name[1]);
// 'u'
// 'o'
§ Les références sont opaques (contenu invisible) et ne peuvent
pas être manipulées par le programmeur.
§ De ce fait, les détails du mécanisme sous-jacent ( détails
d'implémentation) ne sont pas très importants car ils n'affectent
pas le principe général de fonctionnement.
§ Avec les types référence, il faut toujours bien distinguer si l'on
traite la référence (adresse) ou l'objet référencé (contenu).
Cette distinction est très importante, notamment avec les
opérateurs d'égalité (==), d'inégalité (!=) et d'affectation (=) ainsi
que lors des passages en paramètre (invocation de méthodes).
Attention aux effets d'alias (couplage entre variables)
EIA-FR / Jacques Bapst
'a'
2
name
word
1
0
char[] name= {'M','a','r','c'};
char[] word= {'Z', 'u', 't'};
name
0
§ Ces remarques s'appliquent à tous les types référence, c'est-à-dire
aux tableaux et aux objets (que nous verrons plus tard).
En modifiant un élément de
word, on modifie également
le contenu de name!
PR1_05
18
EIA-FR / Jacques Bapst
PR1_05
20
Java / Tableaux
Java / Tableaux
Référence / Objet référencé [2]
Passage de tableaux en paramètre [1]
§ Le mécanisme de passage de paramètres qui a été vu dans le
chapitre consacré aux méthodes s'applique également aux types
référence et notamment aux tableaux.
§ Comparaison et assignation de tableau et de contenu.
char[] c1 = {'a', 'b', 'c'};
char[] c2 = {'a', 'b', 'c'};
char[] c3 = c1;
§ Le passage par valeur de la référence (avec copie locale de cette
dernière) a cependant des implications qu'il est important de bien
comprendre.
if (c1 == c2) System.out.println("c1 égal à c2");
if (c1 == c3) System.out.println("c1 égal à c3");
if (c2 == c3) System.out.println("c2 égal à c3");
§ Dans ce cas, la méthode peut accéder et modifier les valeurs
référencées car c'est la référence à l'objet qui est assignée à la
copie locale (paramètre effectif) lors de l'invocation.
if (c1[0] == c2[0]) System.out.println("c1[0] == c2[0]");
if (c1[0] == c3[0]) System.out.println("c1[0] == c3[0]");
if (c2[0] == c3[0]) System.out.println("c2[0] == c3[0]");
§ On a donc une copie locale de la référence mais pas des valeurs
référencées (c'est efficace à l'exécution mais peut induire des effets
de bord non souhaités).
c3[0] = 'z';
if (c1[0] == c3[0]) System.out.println("c1[0] == c3[0]");
if (c2[0] == c3[0]) System.out.println("c2[0] == c3[0]");
EIA-FR / Jacques Bapst
Remarque : Une méthode qui modifie l'état de certains objets ou tableaux
passés en paramètres doit clairement l'indiquer dans sa
spécification (description).
PR1_05
21
EIA-FR / Jacques Bapst
PR1_05
23
Java / Tableaux
Java / Tableaux
Passage de tableaux en paramètre [2]
Référence / Objet référencé [3]
§ Dans l'exemple ci-dessous, la méthode max() reçoit, au moment
de son l'appel, une copie de la référence du tableau numbers
(paramètre effectif) dans la variable t (paramètre formel).
public static void main(String[] args) {
int[] numbers = {3, 2, 4, 2};
Quand le sage montre la lune,
l'imbécile regarde le doigt !
PR1_05
0
1
2
3
3
2
4
2
int nMax = max(numbers);
System.out.println("Greatest: " + nMax);
}
Lao-Tseu
EIA-FR / Jacques Bapst
numbers
public static int max(int[] t) {
int max = t[0];
for (int i=0; i<t.length; i++) {
if (t[i]>max) max = t[i];
}
return max;
}
22
EIA-FR / Jacques Bapst
t
Console
Greatest: 4
PR1_05
24
Java / Tableaux
Java / Tableaux
Passage de tableaux en paramètre [3]
Méthodes avec paramètre variable [2]
§ Dans le corps de la méthode, les valeurs du paramètre variable sont
lues comme les éléments d'un tableau (selon le type déclaré).
§ Le mécanisme a pour conséquence que la méthode max() peut, si
elle le souhaite, modifier le contenu du tableau t et donc celui de
numbers car c'est la même zone mémoire (alias sur les références) !
numbers
0
1
2
3
3
9
4
2
int nMax = max(numbers);
System.out.println("Greatest: " + nMax);
}
public static int max(int[] t) {
t[1] = 9;
// Caution: side effect !
int max = t[0];
for (int i=0; i<t.length; i++) {
if (t[i]>max) max = t[i];
}
return max;
}
t
Complément
public static void main(String[] args) {
int[] numbers = {3, 2, 4, 2};
§ Exemple :
dispErrors(7, "Erreur de lecture", "Le fichier n'existe pas");
Console
dispErrors(5, "Erreur", "Accès bloqué", "Compte expiré");
Greatest: 9
dispErrors(0);
PR1_05
EIA-FR / Jacques Bapst
25
Java / Tableaux
PR1_05
27
Java / Tableaux
Méthodes avec paramètre variable [1]
Boucle for revisitée (for-each) [1]
§ Il est possible de définir des méthodes comportant un nombre
variable de paramètres.
§ A partir de la version 1.5 du langage, une syntaxe complémentaire
a été introduite pour l'instruction for. Elle permet de parcourir tous
les éléments d'un tableau ou d'une collection de données (itérateur)
en utilisant une syntaxe allégée :
§ Le mécanisme de passage des paramètres variables repose sur
une mise en tableau automatique. Il s'agit seulement d'une
simplification de la syntaxe de déclaration et d'invocation de la
méthode.
§ Syntaxe de déclaration d'un paramètre variable :
Type... NomDuParamètre
§ Exemple :
public static void dispErrors(int cause, String... errText)
§ Une méthode ne peut comporter qu'un seul paramètre variable et
il doit être le dernier dans la liste des paramètres formels.
§ Dans l'exemple donné, les paramètres seront transmis dans un
tableau de chaînes de caractères String[] (le mécanisme est
simplement masqué).
PR1_05
26
Complément
Complément
§ Cette méthode dispErrors() pourra être invoquée avec un nombre
variable d'arguments :
dispErrors(2, "Erreur fatale");
EIA-FR / Jacques Bapst
EIA-FR / Jacques Bapst
public static void dispErrors(int cause, String... errText) {
...
for (int k=0; k<errText.length; k++) {
System.out.println(errText[k]);
}
...
}
for ( type elem : tableau ) instruction
§ Cette forme de l'instruction for est parfois appelée for-each
§ Exemple :
boolean[] message = new boolean[200];
...
for (boolean elem : message) {
if (elem) System.out.println("-");
else
System.out.println(".");
}
...
EIA-FR / Jacques Bapst
PR1_05
28
Java / Tableaux
Boucle for revisitée (for-each) [2]
Complément
§ En utilisant cette nouvelle syntaxe, l'exemple donné précédemment
pour illustrer les méthodes avec paramètres variables pourrait être
codé ainsi :
public static void dispErrors(int cause, String... errText) {
...
for (String text : errText) {
System.out.println(text);
}
...
}
§ Le symbole ":" se lit "in" ("dans").
§ Cette nouvelle syntaxe ne remplace pas la syntaxe de base (elle la
simplifie dans certaines situations particulières ).
§ Chaque fois que l'on doit accéder à l'itérateur (par exemple l'indice
du tableau) dans le corps de la boucle cette syntaxe ne peut pas
être utilisée.
EIA-FR / Jacques Bapst
PR1_05
29
Java / Tableaux
Méthodes utilitaires
Complément
§ La classe Arrays (du package java.util) définit une série
de méthodes statiques utilitaires permettant de manipuler des
tableaux :
•
•
•
•
•
Assignation d'une valeur à certains éléments d'un tableau . . fill()
Test d'égalité du contenu de deux tableaux . . . . . . . . . . . . . . equals()
Tri du contenu d'un tableau . . . . . . . . . . . . . . . . . . . . . . . . . . sort()
Conversion d'un tableau en liste (List) . . . . . . . . . . . . . . . . asList()
Recherche binaire dans un tableau trié . . . . . . . . . . . . . . . . . binarySearch()
§ La classe System (du package java.lang) contient une méthode
statique arraycopy() permettant de copier les éléments spécifiés
d'un tableau dans un autre tableau, à une position donnée (attention
: copie au premier niveau seulement [Shallow copy]).
Le second tableau doit être du même type que le premier. Il peut
même s'agir du même tableau.
§ La méthode clone() de la classe Object peut également être
utilisée pour copier le contenu d'un tableau (Shallow copy) :
int[] b = (int[])a.clone();
EIA-FR / Jacques Bapst
PR1_05
30
Java / Exceptions
Avantages des exceptions
Informatique / Programmation
§ Augmentent la lisibilité du code en séparant les instructions qui
traitent le cas normal des instructions nécessaires au traitement
des erreurs ou des événements exceptionnels.
§ Permettent (voire imposent) la déclaration explicite des exceptions
qu'une méthode peut lever (fait partie de la signature).
§ Forcent le programmeur à prendre en compte (traiter ou propager)
les cas exceptionnels (erreurs ou autres événements) qui sont
déclarés dans les méthodes qu'il invoque.
Programmation orientée objet avec Java
06 : Les exceptions et leur traitement
§ Permettent de créer une hiérarchie d'événements et de les traiter
avec une granularité différente selon les situations.
§ Offrent un mécanisme de propagation automatique ce qui permet
au programmeur de choisir à quel niveau il souhaite traiter
l'exception (celui auquel il est à même de prendre les mesures
adéquates).
Jacques Bapst
[email protected]
EIA-FR / Jacques Bapst
Java / Exceptions
3
Java / Exceptions
Exceptions
Gestion des exceptions
§ En Java, les exceptions sont représentées par des objets de type
Throwable. Il existe plusieurs familles d'exceptions représentées
par différentes sous-classes de Throwable (par ex. Exception).
§ Les exceptions représentent des événements qui peuvent
survenir durant l'exécution d'un programme et qui rompent le
flux normal des instructions.
§ Différentes instructions permettent de gérer les exceptions.
§ Les exceptions sont principalement utilisées pour représenter
des erreurs de différents types : des erreurs matérielles (crash du
disque, ...) des erreurs de programmation (indice d'un tableau hors
limites, ...) des erreurs liées à l'environnement d'exécution (mémoire
insuffisante, ...), des erreurs spécifiques à une librairie (matrice
singulière) ou à une application (numéro d'article non-défini), etc.
§ L'instruction throw sert à générer une exception (on dit
également lever une exception, lancer une exception, …).
§ L'instruction try / catch / finally constitue le cadre dans lequel
les exceptions peuvent être détectées (capturées) et traitées.
§ Le mot-clé throws (à ne pas confondre avec throw) est utilisé dans la
déclaration de méthode (signature) pour annoncer la liste des
exceptions que la méthode peut générer. L'utilisateur de la
méthode est ainsi informé des exceptions qui peuvent survenir
lors de son invocation et peut prendre les mesures nécessaires
pour gérer ces événements exceptionnels (c'est-à-dire les traiter
ou les propager).
§ Les exceptions peuvent également représenter des événements
qui en sont pas à proprement parler des erreurs, mais qui
correspondent à des situations exceptionnelles (prévues) qui
doivent être traitées de manières différentes du flux normal des
opérations (par exemple la fin d'un fichier, un mot de passe incorrect,
des ressources momentanément non-disponibles, …).
EIA-FR / Jacques Bapst
PR1_06
PR1_06
2
EIA-FR / Jacques Bapst
PR1_06
4
Java / Exceptions
Java / Exceptions
Générer (lever) une exception [1]
Traiter une exception [1]
§ Les exceptions peuvent être générées soit :
§ Les instructions susceptibles de lever des exceptions peuvent être
insérées dans un bloc try / catch qui se présente de la manière
suivante :
• par le système, lors de l'exécution de certaines instructions
• par l'exécution de l'instruction throw (dans les classes pré-définies de la
plate-forme Java [librairies] ou dans le code que l'on écrit soi-même )
try {
// Bloc contenant des instructions pouvant générer des exceptions.
§ Parmi les instructions qui génèrent des exceptions, on peut citer :
}
catch (ExceptionType1 e1) {
• La division entière par zéro qui génère
ArithmeticException
// Bloc contenant les instructions qui traitent (capturent) les exceptions
// du type ExceptionType1 (ou d'une de ses sous-classes)
// On peut référencer l'objet exception à l'aide de la variable e1.
• L'indexation d'un tableau hors de ses limites qui génère
ArrayIndexOutOfBoundsException
• L'utilisation d'un tableau ou objet dont la référence vaut null qui génère
NullPointerException
• La création d'un tableau avec une taille négative qui génère
NegativeArraySizeException
}
catch (ExceptionType2 e2) {
// Bloc contenant les instructions qui traitent (capturent) les exceptions
// du type ExceptionType2 (ou d'une de ses sous-classes).
// On peut référencer l'objet exception à l'aide de la variable e2.
}
catch (…) {
• La conversion d'un objet dans un type non compatible qui génère
ClassCastException
…
• ...
// Et ainsi de suite…
}
EIA-FR / Jacques Bapst
PR1_06
5
Java / Exceptions
EIA-FR / Jacques Bapst
7
Java / Exceptions
Générer (lever) une exception [2]
Traiter une exception [2]
§ Si une des instructions contenues dans le bloc try, lève une
exception, le contrôle est passé au premier bloc catch dont le type
d'exception correspond à l'exception qui a été levée (même classe
ou classe parente de l'exception levée).
§ Pour générer explicitement une exception, on utilise l'instruction
throw :
throw exception_object ;
§ L'expression qui suit l'instruction throw doit être un objet qui
représente une exception (un objet de type Throwable).
§ Après l'exécution de la dernière instruction du bloc catch
considéré, le contrôle est passé à l'instruction qui suit le dernier
bloc catch (ou à la clause finally s'il y en a une).
§ Lors de la création de l'objet exception, on peut généralement lui
associer un message (String) qui décrit l'événement.
§ Si aucun bloc catch ne correspond au type d'exception qui a été
levée, l'exception est propagée au niveau supérieur c'est-à-dire
que le contrôle est transféré au traitement d'exception de la
méthode invoquante ou du bloc englobant. Si aucun traitement
n'existe au niveau supérieur pour ce type d'exception, la
propagation se poursuit jusqu'à trouver un bloc catch traitant cette
exception. Si ce n'est pas le cas, le programme se termine avec un
message d'erreur sur la console de sortie (Stack Trace).
public static long factorial(int x) throws Exception {
long result = 1;
if (x<0)
throw new Exception("x doit être >= 0");
while (x > 1) {
result *= x;
x--;
}
return result;
}
EIA-FR / Jacques Bapst
PR1_06
PR1_06
6
EIA-FR / Jacques Bapst
PR1_06
8
Java / Exceptions
Java / Exceptions
Traiter une exception [3]
try {
instr1;
Une exception a été générée
instr2;
instr3;
}
catch (ClockException ce) {
instr4;
instr5;
}
catch (NegativeArgExc na) {
instr6;
instr7;
}
catch (…) {
. . .
}
Suite des instructions
Traiter une exception [5]
§ Il est possible de traiter plusieurs types d'exceptions dans une seule
clause catch en utilisant le symbole '|' comme séparateur.
Oui
§ Les exceptions mentionnées dans une telle liste doivent être
"indépendantes" sur le plan de leur relation hiérarchique. Une des
exceptions ne peut pas être un ancêtre (super-classe) d'une autre
(dans ce cas, mentionner l'exception ancêtre suffit pour traiter toutes celles
de sa "famille").
Est-elle du type ClockException ?
Non
Oui
Est-elle du type NegativeArgExc ?
try {
. . .
}
catch (UnknownUser | IncorrectPassword loginError) {
. . .
}
Non
Oui
Est-elle du type . . . ?
Non
catch (Exception otherError) {
. . .
}
Propagation au niveau supérieur
EIA-FR / Jacques Bapst
9
PR1_06
Java / Exceptions
EIA-FR / Jacques Bapst
Traiter une exception [6]
§ Les divers types d'exception peuvent appartenir à différentes
familles (voir hiérarchie de classes, en fin de chapitre).
§ Une exception spécialisée (par ex. FileNotFoundException) peut
faire partie d'une famille plus vaste (IOException) qui elle-même fait
partie d'une famille plus générale (Exception) etc.
§ Si plusieurs clause catch sont compatibles avec le type d'exception
qui a été levée (font partie de la même famille), c'est la première
qui capturera l'exception et se chargera du traitement.
.
(FileNotFoundException notFound) {
.
(IOException ioErr) {
.
L'ordre des clauses
catch est important !
(Exception genErr) {
.
EIA-FR / Jacques Bapst
11
Java / Exceptions
Traiter une exception [4]
try {
. .
}
catch
. .
}
catch
. .
}
catch
. .
}
PR1_06
PR1_06
10
§ Lorsqu'un problème a été détecté (une exception a été générée) et
que l'on est en mesure de le traiter (au moins partiellement), il y a
différentes mesures que l'on peut envisager, selon les cas, pour
régler la situation.
§ Dans un traitement d'exception (bloc catch) on peut par exemple :
• Régler le problème et recommencer le traitement (nécessite généralement
un boucle ). Idéal mais pas toujours possible.
• Faire quelque chose d'autre à la place (algorithme de substitution).
• Sortir de l'application (System.exit()) après affichage d'un message
(et/ou de la Stack-Trace), écriture dans un fichier log, etc.
• Re-générer l'exception (après avoir effectué certaines opérations ).
• Générer une nouvelle exception (après avoir éventuellement effectué
certaines opérations ).
• Retourner une valeur spéciale ou valeur par défaut (pour une fonction).
• Terminer la méthode (si elle n'a pas de valeur de retour).
• Ne rien faire (ou afficher un message) et continuer (c'est rarement une bonne
solution).
EIA-FR / Jacques Bapst
PR1_06
12
Java / Exceptions
Java / Exceptions
Propagation des exceptions [1]
Propagation des exceptions [3]
public class PropEx {
§ Dans le programme PropEx, lors de la deuxième invocation de la
méthode b(), une exception sera levée dans la méthode d()
(division par zéro).
public static void main(String[] args) {
System.out.println("main starts");
b(5);
b(0);
System.out.println("main ends");
}
//--------------------------------------------// b
//--------------------------------------------public static void b(int i) {
System.out.println("b starts");
try {
System.out.println("b step 1");
c(i);
System.out.println("b step 2");
}
catch (Exception e) {
System.out.println("b catches " + e);
}
System.out.println("b ends");
}
EIA-FR / Jacques Bapst
§ Le déroulement de l'application sera alors altéré et l'exception
sera propagée jusqu'à la méthode b() qui dispose d'un bloc
catch pour traiter cette exception.
b(5) 1ère invocation
b(0) 2ème invocation
main starts
b starts
b step 1
c starts
d starts
d ends
c ends
b step 2
b ends
…
…
b starts
b step 1
c starts
d starts
b catches ArithmeticException: / by zero
b ends
main ends
// Suite...
PR1_06
13
Java / Exceptions
EIA-FR / Jacques Bapst
PR1_06
15
Java / Exceptions
Interprétation de la Stack-Trace [1]
Propagation des exceptions [2]
// …Suite
§ Si, dans l'exemple précédent (PropEx), on supprime tout traitement
d'exception, l'exception provoquée par la division par zéro (dans la
méthode d()) sera propagée jusqu'à la méthode main() qui sera
alors interrompue avec affichage du nom de l'exception et de l'état
de la pile des appels (Stack-Trace) :
//--------------------------------------------// c
//--------------------------------------------public static void c(int i) throws Exception {
System.out.println("c starts");
d(i);
System.out.println("c ends");
}
java.lang.ArithmeticException: / by zero
at javabasic.PropEx.d(PropEx.java:43)
at javabasic.PropEx.c(PropEx.java:37)
at javabasic.PropEx.b(PropEx.java:24)
at javabasic.PropEx.main(PropEx.java:13)
//--------------------------------------------// d
//--------------------------------------------public static void d(int i) throws Exception {
System.out.println("d starts");
int a=10/i;
// Cette instruction peut générer une exception
System.out.println("d ends");
}
Exception in thread "main"
§ Il est important de savoir interpréter ces informations de manière à
localiser rapidement la cause du problème qui a causé l'interruption
de l'application et agir au bon endroit.
}
§ La page suivante décrit comment interpréter cette Stack-Trace.
EIA-FR / Jacques Bapst
PR1_06
14
EIA-FR / Jacques Bapst
PR1_06
16
Java / Exceptions
Java / Exceptions
Interprétation de la Stack-Trace [2]
§ La Stack-Trace décrit (dans
l'ordre inverse) la séquence
(pile) des appels qui ont conduit
à l'interruption de l'application.
Clause finally [2]
§ Un bloc finally est généralement utilisé pour effectuer des
opérations de conclusion (fermeture de fichiers, de connexion
réseau, de base de données, etc.) qui devraient être effectuées
dans tous les cas de figure.
java.lang.ArithmeticException: / by zero
at javabasic.PropEx.d(PropEx.java:43)
at javabasic.PropEx.c(PropEx.java:37)
at javabasic.PropEx.b(PropEx.java:24)
at javabasic.PropEx.main(PropEx.java:13)
Exception in thread "main"
§ La première ligne affichée correspond au type d'exception qui a été
générée (avec, éventuellement, le texte du message qui lui est associé).
Le bloc finally évite donc de devoir placer ces instructions de
conclusion dans le bloc try et dans tous les blocs catch.
§ On trouve ensuite l'enchaînement des invocations de méthodes où
chacune des lignes est structurée de la manière suivante :
§ L'utilisation des instructions break, continue, return ou throw
(dans les blocs try ou catch) n'empêche pas l'exécution
préalable du bloc finally.
. . .
at Package.Classe.Méthode(Fichier_Source:No_de_ligne)
. . .
§ Dans le cas d'une application, on trouvera sur la dernière ligne de la
séquence des appels, la méthode main() qui constitue le point
d'entrée du programme.
EIA-FR / Jacques Bapst
PR1_06
17
Java / Exceptions
§ Le bloc finally est optionnel mais un bloc try doit
obligatoirement être accompagné d'au moins un bloc catch ou
d'un bloc finally (ou naturellement des deux).
EIA-FR / Jacques Bapst
19
Java / Exceptions
Clause finally [1]
Clause finally [3]
§ Exemple d'utilisation de la clause finally :
§ Une clause finally peut être ajoutée à une instruction try /
catch.
try {
openFile(f);
content= readFile(f);
print(content);
}
§ Cette clause définit un bloc d'instructions qui seront exécutées
à la fin de l'instruction try / catch indépendamment du fait que
des exceptions aient été levées ou non. Le bloc finally sera
exécuté dans tous les cas.
catch (InvalidData invdat) {
System.out.println("Les données du fichier sont erronées");
}
§ Si aucune exception n'est levée dans le bloc try , le bloc finally
sera exécuté après la dernière instruction du bloc try.
catch (PrintError prerr) {
System.out.println("Erreur durant l'impression");
}
§ Si une exception est levée dans le bloc try et est capturée par
un bloc catch, le bloc finally sera exécuté après la dernière
instruction du bloc catch.
finally {
closeFile(f);
}
§ Si une exception est levée dans le bloc try et n'est pas capturée
par un bloc catch, le bloc finally sera exécuté avant la
propagation de l'exception au niveau supérieur.
EIA-FR / Jacques Bapst
PR1_06
PR1_06
18
EIA-FR / Jacques Bapst
//--- Effectué dans tous les cas
PR1_06
20
Java / Exceptions
Java / Exceptions
Objet exception
Exceptions contrôlées / non-contrôlées
§ L'objet exception sert principalement de marqueur pour l'événement
qui lui est associé.
§ Dans un traitement d'exception (bloc catch), l'objet exception est
transmis et il peut être utilisé pour obtenir plus d'informations
concernant l'événement.
§ Les exceptions contrôlées (checked) [du type Exception] doivent
être soit traitées (dans une clause catch), soit propagées pour être
traitées à un niveau supérieur (annoncée avec throws dans l'en-tête).
§ Elle ne peuvent pas être ignorées (le compilateur génère une erreur
dans ce cas).
§ Quelques méthodes que l'on peut utiliser avec les objets exception :
getMessage()
: retourne un String contenant le message
(texte) associé à l'exception
toString()
: retourne un String contenant le nom de
l'exception suivi du message associé
printStackTrace()
: affiche sur la console de sortie le nom de
l'exception, le message associé ainsi que l'état
de la pile des appels qui ont conduit au
traitement de l'exception (Stack-Trace)
getStackTrace()
: retourne les informations de la Stack-Trace sous
forme d'un tableau de StackTraceElement
EIA-FR / Jacques Bapst
PR1_06
§ Pour les exceptions non-contrôlées (unchecked) [du type
RuntimeException ou Error], le programmeur a le choix de les traiter
ou de les ignorer (sans erreur à la compilation).
§ Si une telle exception survient et qu'elle n'est traitée nulle part, elle
sera alors propagée et "remontera" jusqu'à la méthode main()
interrompant ainsi brutalement l'application.
21
Java / Exceptions
EIA-FR / Jacques Bapst
PR1_06
Java / Exceptions
Hiérarchie de classes
La classe Error
§ Dans le langage Java, toutes les exceptions sont représentées par
des objets qui spécialisent la classe de base Throwable.
§ La classe Error représente généralement des erreurs sévères qui
surviennent dans la machine virtuelle.
§ Trois sous-classes de Throwable sont pré-définies :
Error, Exception et RuntimeException selon l'arborescence
suivante :
§ Le langage n'impose par que les programmeurs traitent ce type
d'exceptions car elles ne devraient pas survenir dans un
environnement sain (machine virtuelle correctement installée).
Throwable
Error
§ On ne traite généralement pas ce type d'exceptions dans une
application standard sauf éventuellement au niveau le plus haut
pour informer l'utilisateur (si c'est encore possible) et éviter le crash
brutal de l'application.
Exception
§ D'autre part, les applications ne devraient pas générer (dans des
instructions throw) ce genre d'exceptions.
RuntimeException
Exceptions
non-contrôlées
EIA-FR / Jacques Bapst
23
§ Exemples : OutOfMemoryError, StackOverflowError,
AssertionError (Erreur de conception)
Exceptions
contrôlées
PR1_06
22
EIA-FR / Jacques Bapst
PR1_06
24
Java / Exceptions
Java / Exceptions
Créer de nouveaux types d'exceptions
La classe Exception
§ Un grand nombre de sous-classes de Exception sont pré-définies
dans les classes de la plate-forme Java
§ Exemples : PrintException, IOException
§ Les exceptions spécifiques à une librairie ou à une application sont
généralement représentées par des sous-classes de Exception.
§ La classe RuntimeException représente une sous-classe
particulière de Exception (voir page suivante).
§ Pour créer ses propres types d'exceptions, il suffit de dériver
(spécialiser) une classe de type Throwable (choisir une des
classes existantes proche de celle que l'on souhaite créer ou, sinon,
dériver la classe générale Exception).
§ Généralement, dans cette sous-classe, on crée uniquement deux
constructeurs : un constructeur sans paramètre et un constructeur
qui prend un message (String) en paramètre.
§ On crée rarement de nouveaux champs ou de nouvelles méthodes.
public class ClockException extends Exception {
public ClockException() {
super();
}
§ Le langage impose que les exceptions de type Exception (qui ne
sont pas une sous-classe de RuntimeException) soient traitées par les
applications (en plaçant les instructions critiques dans un bloc try /
catch, ou en déclarant l'exception dans la signature de la méthode à l'aide
du mot-clé throws déléguant ainsi le traitement au niveau supérieur).
EIA-FR / Jacques Bapst
PR1_06
25
Java / Exceptions
}
EIA-FR / Jacques Bapst
PR1_06
27
Java / Exceptions
Utiliser des exceptions personnalisées
La classe RuntimeException
§ La classe RuntimeException représente une sous-classe
particulière (exceptions non-contrôlées) de la classe Exception.
§ L'utilisation des types d'exceptions que l'on a créés est identique à
l'utilisation des types d'exceptions pré-définis.
§ Elle représente des erreurs qui sont détectées par la machine
virtuelle durant l'exécution de l'application.
Par exemple, l'exception NullPointerException indique que
la référence à un objet n'est pas définie (null).
Cette exception peut potentiellement survenir lors de l'exécution de
n'importe quelle instruction qui manipule un objet.
§ De ce fait, le langage n'impose pas que les exceptions de type
RuntimeException (et de ses sous-classes) soient traitées par
les applications (ce qui serait extrêmement lourd et contraignant).
§ Si nécessaire, les applications peuvent cependant traiter ce type
d'exceptions (dans un bloc try / catch) et prendre ainsi les mesures
adéquates.
§ Exemples : ArithmeticException,
ArrayIndexOutOfBoundsException
EIA-FR / Jacques Bapst
public ClockException(String message) {
super(message);
}
A prendre tel quel pour l'instant
(sera étudié ultérieurement)
§ La classe Exception représente la classe de base de la plupart
des exceptions qui sont générées (throw) et traitées (catch) dans
les applications (exceptions contrôlées).
PR1_06
26
. . .
if (hour < 0 || hour > 23) {
throw new ClockException("Heure incorrecte");
}
. . .
. . .
try {
. . .
}
catch (ClockException clockErr) {
System.out.println(clockErr);
. . .
}
catch (Exception otherErr) {
. . .
}
. . .
EIA-FR / Jacques Bapst
PR1_06
28
Java / Chaînes de caractères (String / StringBuffer / StringBuilder)
Comparaison de chaînes
Informatique / Programmation
§ Comme pour tous les types référence, l'opérateur "==" compare les
références et non pas les objets référencés (les chaînes de caractères).
§ La méthode equals() permet, elle, de comparer deux chaînes de
caractères (objets référencés) et retourne true si elles sont égales.
§ La méthode compareTo() remplace les opérateurs "plus petit", "égal",
"plus grand" en utilisant l'ordre lexicographique (ordre du dictionnaire) et
en retournant respectivement une valeur (int) négative, 0 ou positive.
Programmation orientée objet avec Java
07 : Chaînes de caractères
String myString = "abc";
String otherStr = "abcdef";
if (myString == otherStr)
System.out.println("Same string object");
Jacques Bapst
if (myString.equals(otherStr))
System.out.println("Same contents");
[email protected]
if (myString.compareTo(otherStr) < 0)
System.out.println(myString + " smaller than " + otherStr);
EIA-FR / Jacques Bapst
Java / Chaînes de caractères (String / StringBuffer / StringBuilder)
PR1_07
3
Java / Chaînes de caractères (String / StringBuffer / StringBuilder)
Chaînes de caractères (String)
Objets String immuables
§ Les objets de type String sont immuables : une fois créés ils
ne peuvent plus être modifiés. Naturellement, la variable de type
référence peut changer de valeur, et pointer vers une nouvelle
chaîne (créée à un autre emplacement).
§ En Java les chaînes de caractères sont représentées par des
objets de type String (une classe prédéfinie).
§ Les chaînes de caractères ne font donc pas partie des types
primitifs mais sont des types référence.
"Hello"
String someText = "Hello";
someText = "Bonjour";
§ Une syntaxe particulière est utilisée pour définir des littéraux de
type String : on entoure le texte avec des guillemets ("…").
someText
"Bonjour"
§ On peut insérer des séquences d'échappement (identiques à celles
définies pour le type char) dans les littéraux de type String.
§ Les objets immuables ont l'avantage de pouvoir être partagés sans
risque et l'on évite les problèmes d'alias (ð optimisations possibles).
§ La déclaration et création d'une variable de type String s'effectue
de la manière suivante :
§ Par contre, si l'on manipule fréquemment des objets de type String
(à l'intérieur de boucles par exemple) cela peut conduire à la création
d'un nombre considérable d'objets (temporaires) avec un coût non
négligeable (ressources mémoires et temps d'exécution).
String someText = "Hello";
"Hello"
§ Il est préférable dans ce cas de déclarer et utiliser des objets de
type StringBuffer ou StringBuilder qui sont eux modifiables
(voir pages suivantes).
someTexte
EIA-FR / Jacques Bapst
PR1_07
2
EIA-FR / Jacques Bapst
PR1_07
4
Java / Chaînes de caractères (String / StringBuffer / StringBuilder)
Java / Chaînes de caractères (String / StringBuffer / StringBuilder)
Opérations sur les chaînes [1]
Opérations sur les chaînes [3]
§ La classe String dispose d'un grand nombre de méthodes pour
traiter les chaînes de caractères. Les exemples qui suivent n'en
sont qu'une illustration sommaire.
§ L'opérateur "+" permet de concaténer (mettre bout à bout) des
chaînes de caractères.
§ Si un des deux opérandes de l'opérateur "+" est un String , l'autre
opérande sera, si nécessaire, automatiquement converti en un objet
de type String (par invocation de la méthode toString()).
§ La méthode length() permet de connaître la longueur d'une chaîne
de caractères (nombre de caractères).
§ La méthode charAt() permet de retrouver le caractère situé à la
position n d'une chaîne (0 £ n £ length() -1).
String myText = "Hello";
String
String
s1 = myText + " Mark";
§ La méthode substring() retourne une sous-chaîne d'une chaîne
donnée. Les paramètres déterminent la position initiale et la
position finale (+1) de la sous-chaîne dans la chaîne originelle.
rec = "Hello" + s1 + 3 + ')';
String
int
char
String
String
Remarque : Les objets de type String étant immuables, la concaténation est
implémentée en créant un objet temporaire de type StringBuffer
qui est utilisé ensuite pour créer un nouvel objet de type String.
C'est donc une opération assez lourde.
EIA-FR / Jacques Bapst
PR1_07
Complément
§ Dans les librairies de base, il existe souvent plusieurs méthodes
pour effectuer un même type de conversion.
d = Double.parseDouble("3.14");
à 3.14
String
s = String.valueOf('Z');
à "Z"
boolean b = (i > 10);
à true
String
t = (new Boolean(b)).toString();
à "true"
String
t = Boolean.toString(b);
à "true"
EIA-FR / Jacques Bapst
// Idem
10
'a'
"me"
"YES"
PR1_07
7
§ La méthode split() permet de découper une chaîne de caractères
sur la base d'un séparateur qui est exprimé sous la forme d'une
expression régulière (regex). La méthode retourne le résultat dans
un tableau de String qui contient les fragments découpés.
§ Ces méthodes se trouvent soit dans la classe String, soit dans
les classes Wrapper associées aux types primitifs ( Byte, Short,
Integer, Long, Float, Double, Character, Boolean ).
double
=
=
=
=
Opérations sur les chaînes [4]
§ Différentes méthodes permettent de convertir des valeurs de types
primitifs en objets de type String et inversement (voir la tabelle qui
figure à la fin du premier chapitre du document de cours).
à 43
i
c
s
t
Java / Chaînes de caractères (String / StringBuffer / StringBuilder)
Opérations sur les chaînes [2]
i = Integer.parseInt("43");
//
//
//
//
EIA-FR / Jacques Bapst
5
Java / Chaînes de caractères (String / StringBuffer / StringBuilder)
int
name = "James Bond";
i = name.length();
c = name.charAt(1);
s = name.substring(2, 4);
t = "Yes".toUpperCase();
§ La syntaxe à utiliser pour les expressions régulières est définie dans
la classe Pattern (java.util.regex).
public static void main(String[] args) {
String
path = "usr/lib/ruby/test.rb" ;
String[] elems;
String sepPattern1 = "/";
// Slash separator
elems = path.split(sepPattern1); elems ® { "usr", "lib", "ruby", "test.rb" }
String sepPattern2 = "/|\\."; // Slash or dot separator
elems = path.split(sepPattern2); elems ® { "usr", "lib", "ruby", "test", "rb" }
}
PR1_07
6
EIA-FR / Jacques Bapst
PR1_07
8
Java / Chaînes de caractères (String / StringBuffer / StringBuilder)
Java / Chaînes de caractères (String / StringBuffer / StringBuilder)
Formatage de chaînes [1]
Classe StringBuffer [1]
§ Contrairement à la classe String, la classe StringBuffer permet
de créer des chaînes de caractères modifiables (la taille
et le contenu peuvent varier durant l'exécution de l'application).
§ Cette méthode statique nommée format() retourne une chaîne de
caractères formatée et prend en paramètre une chaîne de formatage
(qui doit respecter une certaine syntaxe), ainsi qu'un nombre
variable d'arguments (de type Object ou de types primitifs qui seront
automatiquement convertis par le nouveau mécanisme d'autoboxing).
§ Exemple :
String s = String.format("%.2f", v);
dans ce cas, si v = 1.56789f, alors s = "1.57"
§ La notion de capacité (Capacity) représente la taille du buffer
interne qui mémorise la chaîne de caractères (nombre total de
Complément
Complément
§ A partir de la version 1.5 du langage, une méthode de formatage
assez puissante a été introduite dans la classe String.
§ La syntaxe de la chaîne de formatage est relativement complexe et
sa description se trouve dans l'API de la classe Formatter (du
package java.util).
caractères disponibles avant de devoir agrandir la taille du buffer interne).
§ La capacité est automatiquement augmentée lorsque c'est
nécessaire. La capacité initiale peut être définie lors de la création
d'un objet StringBuffer (paramètre du constructeur, 16 par défaut ).
§ Ne pas confondre capacité et longueur d'un objet StringBuffer.
0
1
U n
2
3
4
5
6
7
8
9 10 11 12 13 14 15 16 17 18 19
t e x t e
length() = 8
EIA-FR / Jacques Bapst
PR1_07
EIA-FR / Jacques Bapst
9
Java / Chaînes de caractères (String / StringBuffer / StringBuilder)
PR1_07
Classe StringBuffer [2]
§ Cette nouvelle méthode de formatage est largement inspirée de
celle de la méthode printf() que l'on trouve dans le langage C (elle
n'est pas totalement équivalente mais très fortement compatible).
§ Pour créer un objet de type StringBuffer, on doit utiliser
l'opérateur new(…) (pas de syntaxe simplifiée).
§ Une méthode printf() a d'ailleurs été ajoutée dans la classe
PrintStream et peut donc être invoquée sur les flux de sortie
System.out et System.err.
§ Création en définissant une capacité initiale :
Complément
StringBuffer someText = new StringBuffer("Hello");
§ Exemples :
int
i = 250;
float v = 1.23456f;
System.out.printf("v with 3 digits %.3f %n", v);
System.out.printf("Hex/Octal %1$x/%1$o %n", i);
System.out.printf("%5d%8.3f %n", i, v);
// Création d'une chaîne vide avec une capacité de 2000 caracères
StringBuffer sb = new StringBuffer(2000);
// Ajout d'une chaîne littérale (String)
sb.append("Bonjour");
System.out.println(sb.length());
System.out.println(sb.capacity());
//
7
// 2000
sb.append(" à tous !");
v with 3 digits 1.235
Hex/Octal fa/372
250
1.235
EIA-FR / Jacques Bapst
11
Java / Chaînes de caractères (String / StringBuffer / StringBuilder)
Formatage de chaînes [2]
Complément
capacity() = 20
System.out.println(sb.length());
System.out.println(sb.capacity
System.out.println(sb.capacity());
PR1_07
10
EIA-FR / Jacques Bapst
//
16
// 2000
PR1_07
12
Java / Chaînes de caractères (String / StringBuffer / StringBuilder)
Java / Chaînes de caractères (String / StringBuffer / StringBuilder)
Opérations sur les StringBuffer
Classe StringBuilder
append()
Ajoute un élément à la fin de la chaîne de caractères
(surcharge pour différents types d'éléments)
insert()
Insère un élément à une position donnée de la chaîne de
caractères (surcharge pour différents types d'éléments)
replace()
Remplace une partie d'une chaîne de caractères par une
autre
delete()
Efface une portion donnée d'une chaîne de caractères
setCharAt()
Remplace un caractère à une position donnée
deleteCharAt()
Efface (supprime) un caractère à une position donnée
substring()
Extrait une sous-chaîne
toString()
Convertit le contenu en type String
EIA-FR / Jacques Bapst
PR1_07
§ Dans la librairie standard de la plateforme Java, on trouve
également la classe StringBuilder.
Complément
Complément
§ Différentes méthodes permettent de manipuler les objets de type
StringBuffer :
13
Java / Chaînes de caractères (String / StringBuffer / StringBuilder)
Conversions String ó StringBuffer
§ Pour convertir un objet de type String en un objet de type
StringBuffer on utilise le constructeur (opérateur new(…)).
String
s1
= "Hello";
Complément
StringBuffer sBuf = new StringBuffer(s1);
§ Pour convertir un objet de type StringBuffer en un objet de type
String on utilise la méthode toString(…) ou substring(…).
StringBuffer vText = new StringBuffer();
vText.append("Un texte");
String s2 = vText.toString();
String s3 = vText.substring(3, 6);
EIA-FR / Jacques Bapst
// s3 <-- "tex"
PR1_07
14
§ Son API est compatible avec celle de la classe StringBuffer
qu'elle peut remplacer dans toutes les situations où le code
s'exécute dans un seul thread (c'est-à-dire dans tous les cas où il n'est
pas indispensable que le code soit thread-safe).
§ La plupart des méthodes de la classe StringBuilder s'exécutent
plus rapidement que celles de la classe StringBuffer.
§ Toutes les indications données dans les pages précédentes pour la
classe StringBuffer s'appliquent également à la classe
StringBuilder.
EIA-FR / Jacques Bapst
PR1_07
15
Java / Entrées / Sorties (I/O)
Flux (Stream)
Informatique / Programmation
§ La notion de flux (Stream) caractérise un chemin (une voie) de
communication entre une source d'information et sa destination.
Programmation orientée objet avec Java
08 : Entrées / Sorties (I/O)
§ L'accès aux informations s'effectue de manière séquentielle.
§ Les librairies Java distinguent deux genres de flux :
Jacques Bapst
• Les flux binaires (Byte Stream) qui peuvent représenter des données
quelconques (nombres, données structurées, programmes, sons, images, … )
• Les flux de caractères (Character Stream) qui représentent des
textes (chaînes de caractères) au format Unicode.
[email protected]
EIA-FR / Jacques Bapst
Java / Entrées / Sorties (I/O)
3
Java / Entrées / Sorties (I/O)
Entrées / Sorties (I/O)
Utilisation des flux
§ La communication avec un flux comprend trois phases :
§ Les entrées/sorties (Input/Output ou I/O) permettent à un
programme de communiquer avec certains périphériques.
• L'ouverture du flux, en entrée (pour la lecture)
ou en sortie (pour l'écriture)
§ Les entrées/sorties permettent par exemple :
• de lire et d'écrire sur la console
• La répétition de la lecture ou de l'écriture
des données (généralement des bytes ou
des caractères)
(lecture au clavier et affichage à l'écran en mode 'caractères')
• d'accéder aux fichiers et répertoires des disques
• de communiquer avec d'autres applications
Open
Read / Write
N
End
?
Y
• La fermeture du flux
(localement ou au travers du réseau)
§ Les librairies de la plate-forme Java offrent un grand nombre de
classes dédiées aux entrées/sorties. La plupart des classes se
trouvent dans le package java.io (qui comporte plus de 50 classes !).
PR1_08
Close
§ Quelques classes importantes pour utiliser les flux courants :
§ Au fil des versions, d'autres packages sont venus compléter la
librairie. Il y a notamment le package java.nio, le package
java.nio.file, etc.
EIA-FR / Jacques Bapst
PR1_08
2
Flux d'entrée
Flux de sortie
Flux binaires
DataInputStream
DataOutputStream
Flux de caractères
BufferedReader
PrintWriter
EIA-FR / Jacques Bapst
PR1_08
4
Java / Entrées / Sorties (I/O)
Java / Entrées / Sorties (I/O)
Lecture et écriture des flux
Écriture d'un fichier texte
§ Pour lire un fichier texte il faut ouvrir un flux d'entrée
• La classe FileReader constitue une des couches de base et comporte
les méthodes élémentaires pour lire le flux depuis le système de fichiers
§ Pour écrire un fichier texte il faut ouvrir un flux de sortie
• La classe FileWriter constitue une des couches de base et comporte
les méthodes élémentaires pour écrire le flux sur le système de fichiers
printf(String format, Object... args)
§ La lecture et l'écriture de fichiers textes sont réalisées en enrobant la
couche de base avec des outils de plus haut niveau (imbrication)
• Mémoire tampon (buffer) pour minimiser les accès au disque
• Conversion bytes ó caractères (encodage Unicode)
• Découpage en lignes / Insertion des retours à la ligne, etc.
§ Illustration (pour l'écriture) :
PrintWriter
BufferedWriter
§ Pour la syntaxe du texte de formatage, voir description dans l' API de
la classe java.util.Formatter
• Exemples
p.printf("%.2f", resultScore);
p.printf("Nombre %d
nbItems,
File-System
(par ex. disque)
Prix %ld
price,
Total %9ld\n",
price*nbItems);
p.printf("%5d%8.3f %n", i, v);
FileWriter
EIA-FR / Jacques Bapst
§ En plus des méthodes print() et println() la classe
PrintWriter comporte également la méthode printf() qui a été
décrite dans le chapitre précédent (formatage des chaînes de
caractères) et qui permet de formater le texte écrit dans le fichier.
PR1_08
5
Java / Entrées / Sorties (I/O)
EIA-FR / Jacques Bapst
PR1_08
7
Java / Entrées / Sorties (I/O)
Écriture d'un fichier texte
Lecture d'un fichier texte
§ Pour écrire séquentiellement dans un fichier de texte on peut utiliser
la classe PrintWriter de la manière suivante:
• Ouverture
§ Pour lire séquentiellement le contenu d'un fichier de texte on peut
utiliser la classe BufferedReader de la manière suivante :
• Ouverture
String filename = "C:\\Temp\\TestOut.txt";
PrintWriter p = new PrintWriter(
new BufferedWriter(
new FileWriter(filename)));
String filename = "C:\\Temp\\TestIn.txt";
BufferedReader r = new BufferedReader(
new FileReader(filename));
• Lecture (ligne par ligne)
String s;
s = r.readLine();
while (s != null) {
//--- Tant qu'il y a encore des lignes...
System.out.println(s);
s = r.readLine();
}
• Écriture
p.print("Hello");
p.println(" world" + 3*2);
p.println("Fin du fichier " + filename);
• Fermeture
p.close();
• Fermeture
r.close();
EIA-FR / Jacques Bapst
PR1_08
6
EIA-FR / Jacques Bapst
PR1_08
8
Java / Entrées / Sorties (I/O)
Java / Entrées / Sorties (I/O)
Lecture d'un fichier texte
Lecture au clavier
§ La classe Scanner (java.util) offre différentes méthodes pour
décomposer les données d'un flux de caractères ou d'un String.
§ La lecture au clavier s'effectue en imbriquant (en enrobant) le flux
standard (System.in) dans deux constructeurs de classes qui se
chargeront de la conversion des octets en caractères Unicode et
de la mise en place d'une mémoire tampon intermédiaire.
• Ouverture
String filename = "D:\\Foo\\Config\\Init.cfg";
Scanner scf = new Scanner(new BufferedReader(
new FileReader(filename)));
§ Lecture au clavier :
• Lecture (ligne par ligne, utilisation d'un 2ème Scanner pour analyser chaque ligne )
String line;
while (scf.hasNextLine()) {
line = scf.nextLine();
Scanner scs = new Scanner(line);
scs.useDelimiter("=");
//--- Séparateur (regex pattern)
String key = scs.next();
float val = scs.nextFloat();
Length=1.2
. . .
Width=5.5
}
Depth=0.27
• Fermeture
String s = keyboard.readLine();
Remarques : La méthode readLine() attend jusqu'à ce que l'utilisateur introduise
des caractères au clavier et termine la saisie en pressant sur la
touche Return (Enter).
Le caractère fin de ligne n'est pas inclus dans le String retourné.
Si l'utilisateur presse uniquement sur Return, le String sera vide
(longueur = 0).
Contenu du fichier
Init.cfg
scf.close();
EIA-FR / Jacques Bapst
BufferedReader keyboard = new BufferedReader(
new InputStreamReader(System.in));
. . .
9
PR1_08
Java / Entrées / Sorties (I/O)
EIA-FR / Jacques Bapst
Lecture au clavier
§ Les flux suivants sont prédéfinis dans la classe System.
Ces flux sont toujours ouverts et on ne les ferme pas.
Entrée standard (lecture du clavier)
[ InputStream ]
Sortie standard (affichage à l'écran)
[ PrintStream ]
Sortie des messages d'erreur
[ PrintStream ]
(souvent identique à out par défaut)
§ Écriture sur la console :
System.out.print("Résultats : ");
//--- Reste sur la même ligne
System.out.println(5*4 + ", " + 6);
System.out.println(5*4 + ", " + 4+2);
11
Java / Entrées / Sorties (I/O)
Entrées/Sorties standard (console)
• System.in
• System.out
• System.err
PR1_08
§ Une autre manière de faire (souvent plus pratique) est d'utiliser la
classe Scanner (java.util) qui permet également de saisir mais,
en plus, de transformer et d'interpréter ce qui a été saisi au clavier.
§ Exemple d'utilisation :
Scanner scan = new Scanner(System.in);
System.out.print("Enter an integer (or 'x' to exit) : ");
while (scan.hasNextInt()) {
int i = scan.nextInt();
System.out.println("Value = " + i);
System.out.print("Enter an integer (or 'x' to exit) : ");
}
//--- Attention au piège !
Remarques : La classe Scanner offre de nombreuses possibilités pour
décomposer et interpréter les informations lues.
System.err.println("Erreur : Nom de fichier incorrect");
Pour plus de détail il faut consulter la documentation (API).
EIA-FR / Jacques Bapst
PR1_08
10
EIA-FR / Jacques Bapst
PR1_08
12
Java / Entrées / Sorties (I/O)
Java / Entrées / Sorties (I/O)
Importation des classes I/O
Hiérarchie de la classe IOException
§ La plupart des classes d'entrées/sorties se trouvent dans la librairie
(package) java.io (ou év. dans java.nio).
§ Tout programme qui utilise des entrées/sorties (sauf s'il se limite
aux flux standard) devra préalablement importer toutes les classes
externes nécessaires.
§ On utilisera pour cela la pseudo-instruction :
import java.io.*;
§ Cette instruction doit être placée avant la déclaration de la classe
qui utilise les entrées/sorties (juste après package …).
§ Elle a pour effet de rendre visible toutes les classes contenues
dans le paquetage java.io (importation sélective également possible).
§ Pour pouvoir utiliser la classe Scanner il faut également l'importer :
import java.util.Scanner;
EIA-FR / Jacques Bapst
PR1_08
13
Java / Entrées / Sorties (I/O)
java.lang.Throwable
+-- java.lang.Exception
+-- java.io.IOException
+-- ChangedCharSetException
+-- CharacterCodingException
+-- CharConversionException
+-- CloseChannelException
+-- EOFException
+-- FileNotFoundException
+-- FileLockInterruptionException
+-- MalformedURLException
+-- ProtocolException
+-- SocketException
+-- UnknownHostException
+-- UnsupportedEncodingException
+-- ZipException
+-- . . .
EIA-FR / Jacques Bapst
Plusieurs de ces
classes
comportent
elles-mêmes des
sous-classes
PR1_08
15
Java / Entrées / Sorties (I/O)
Traitement des exceptions
Lecture séquentielle d'un fichier texte
§ La plupart des opérations d'entrées/sorties risquent de générer des
exceptions du type IOException (une sous-classe d'Exception).
§ Ces exceptions (contrôlées) sont déclarées dans la signature
des méthodes concernées et le compilateur impose donc au
programmeur de les traiter ou de déclarer leur propagation.
§ Il faut éviter de mettre des instructions try / catch à chaque ligne.
§ Grâce au mécanisme de propagation des exceptions, il est possible
de concentrer le traitement à un seul endroit (ou à quelques endroits
stratégiques judicieusement choisis).
§ Dans les applications, il faut trouver le bon compromis et placer
les traitements d'exception aux endroits où l'on peut prendre les
mesures adéquates et/ou informer correctement l'utilisateur.
• Pas de message du genre :
"Erreur d'entrée/sortie"
• Mais plutôt un message clair : "Le fichier C:\Image\Tx1.gif n'existe pas"
EIA-FR / Jacques Bapst
§ La classe IOException comporte un grand nombre de sousclasses correspondant à différents types d'événements qui peuvent
survenir lorsqu'on travaille avec les entrées/sorties.
PR1_08
14
import java.io.*;
public class Pg1 {
public static void main(String [] args) {
String
l, w, filename;
BufferedReader f, keyboard;
try {
keyboard = new BufferedReader(new InputStreamReader(System.in));
System.out.print("Entrer le nom du fichier : ");
filename = keyboard.readLine();
f = new BufferedReader(new FileReader(filename));
l = f.readLine();
while (l != null) {
if (l.charAt(0)=='#')
System.out.println("----------");
else
System.out.println(l);
l = f.readLine();
}
f.close();
}
catch (IOException e) {
System.err.println("Erreur: " + e);
}
}
}
EIA-FR / Jacques Bapst
PR1_08
16
Java / Entrées / Sorties (I/O)
Java / Entrées / Sorties (I/O)
Décomposition (parsing) des données lues
Spécification de Scanner
Method Summary (Extract)
§ Les données enregistrées dans des fichiers textes sont
généralement structurées et nécessitent une phase d'analyse et
de décomposition (parsing) avant de pouvoir les utiliser.
boolean
Returns true if there is another line in the input of this scanner.
boolean
String
next()
Finds and returns the next complete token from this scanner.
Classes StringTokenizer et StreamTokenizer
Classe Scanner
Méthode split() de la classe String
Classes Pattern et Matcher (package java.util.regex)
§ La classe StringTokenizer est la plus ancienne et, si elle est
parfois plus performante, elle est cependant moins flexible que
Scanner ou split() qui se basent sur des Expressions régulières
(regex pattern).
Complément
Complément
hasNext…()
Returns true if the next token in this scanner's input can be interpreted as a …
§ La plateforme Java offre différents outils pour faciliter ce travail,
par exemple :
•
•
•
•
hasNextLine()
String
next(String pattern)
Returns the next token if it matches the pattern constructed from the specified string.
boolean
nextBoolean()
Scans the next token of the input into a boolean value and returns that value.
double
nextDouble()
Scans the next token of the input as a double.
int
nextInt()
Scans the next token of the input as a int.
String
nextLine()
Advances this scanner past the current line and returns the input that was skipped.
…
next…()
Scans the next token of the input as a …
Scanner
skip(String pattern)
Skips input that matches a pattern constructed from the specified string.
Scanner
useDelimiter(String pattern)
Sets this scanner's delimiting pattern to a pattern constructed from the specified String.
EIA-FR / Jacques Bapst
PR1_08
EIA-FR / Jacques Bapst
17
Java / Entrées / Sorties (I/O)
PR1_08
19
Java / Entrées / Sorties (I/O)
Spécification de Scanner
Spécification de StringTokenizer
Constructor Summary (Extract)
Constructor Summary
Scanner(InputStream source)
StringTokenizer(String str)
Constructs a new Scanner that produces values scanned from the specified input stream.
Constructs a string tokenizer for the specified string.
Scanner(Readable source)
StringTokenizer(String str, String delim)
Constructs a new Scanner that produces values scanned from the specified source
Constructs a string tokenizer for the specified string.
Scanner(String source)
StringTokenizer(String str, String delim, boolean returnDelims)
Constructs a new Scanner that produces values scanned from the specified string.
Complément
Complément
Constructs a string tokenizer for the specified string.
Method Summary (Extract)
String
findInLine(String pattern)
Attempts to find the next occurrence of a pattern constructed from the specified string, ignoring delimiters.
boolean
hasNext()
Returns true if this scanner has another token in its input.
boolean
hasNext(String pattern)
Returns true if the next token matches the pattern constructed from the specified string.
boolean
int
Calculates the number of times that this tokenizer's nextToken method can be called (before raising an exception).
boolean
hasNextDouble()
hasNextInt()
boolean
hasMoreTokens()
Object
nextElement()
String
nextToken()
String
nextToken(String delim)
Returns the same value as the nextToken method, except that its declared return value is Object rather than String.
PR1_08
Returns the next token from this string tokenizer.
Returns the next token in this string tokenizer's string.
Returns true if the next token in this scanner's input can be interpreted as an int value in the default radix using the
nextInt() method.
EIA-FR / Jacques Bapst
hasMoreElements()
Returns the same value as the hasMoreTokens method.
Returns true if the next token in this scanner's input can be interpreted as a double value using the nextDouble() method.
boolean
countTokens()
Tests if there are more tokens available from this tokenizer's string.
hasNextBoolean()
Returns true if the next token in this scanner's input can be interpreted as a boolean value using a case insensitive pattern
created from the string "true|false".
boolean
Method Summary (Extract)
18
EIA-FR / Jacques Bapst
PR1_08
20
Java / Entrées / Sorties (I/O)
Java / Entrées / Sorties (I/O)
Fichiers à accès direct [1]
import java.util.StringTokenizer; import java.io.*;
public class Pg2 {
public static void main(String [] args) {
String
l, w, filename;
StringTokenizer st;
BufferedReader f, keyboard;
try {
keyboard = new BufferedReader(new InputStreamReader(System.in));
System.out.print("Entrer le nom du fichier : ");
filename = keyboard.readLine();
f = new BufferedReader(new FileReader(filename));
l = f.readLine();
while (l != null) {
st = new StringTokenizer(l);
while (st.hasMoreTokens()) {
System.out.print("(" + st.nextToken() + ")");
}
System.out.println();
l = f.readLine();
}
f.close();
}
catch (IOException e) {
System.err.println("Erreur: " + e);
}
}
}
EIA-FR / Jacques Bapst
PR1_08
§ La classe RandomAccessFile (assez indépendante des autres classes
du package java.io) permet de lire et d'écrire dans un fichier à des
positions arbitraire (accès direct, accès aléatoire).
Complément
Complément
Utilisation de StringTokenizer
§ Un curseur (File Pointer) peut être positionné à un emplacement
quelconque et les opérations de lecture/écriture auront lieu à partir
de cet endroit (après l'opération, le curseur sera automatiquement
positionné après le dernier byte lu ou écrit).
§ Lors de l'ouverture du fichier, on indique le fichier à traiter ainsi que
le mode d'accès :
• "r" : lecture uniquement
• "rw" : lecture et écriture
§ Si le fichier n'existe pas, il sera créé à l'emplacement indiqué (selon
les paramètres du constructeur).
EIA-FR / Jacques Bapst
21
Java / Entrées / Sorties (I/O)
Fichiers à accès direct [2]
§ Pour décomposer une chaîne de caractères, il existe également la
méthode split() qui se trouve dans la classe String.
§ Exemple d'utilisation avec un accès en lecture/écriture dans un
fichier binaire existant :
RandomAccessFile f = new RandomAccessFile("config.dat", "rw");
Complément
Complément
§ Pour le découpage de la chaîne, cette méthode se base sur une
expression régulière dont la syntaxe est définie dans la classe
Pattern (java.util.regex).
str
= "Mots, séparés, par, des, virgules";
String[] words = str.split(", ");
for (int i=0; i<words.length; i++) {
System.out.println(words[i]);
}
Mots
séparés
par
des
virgules
EIA-FR / Jacques Bapst
23
Java / Entrées / Sorties (I/O)
Méthode split()
String
PR1_08
PR1_08
22
f.seek(50);
byte[] data = new byte[100];
f.read(data);
int i = f.readInt();
f.seek(50);
f.writeInt(i);
f.write(data);
f.close();
EIA-FR / Jacques Bapst
//
//
//
//
//
//
//
//
Déplacement vers le byte 50 du fichier
Crée un buffer pour contenir les données
Lit 100 bytes du fichier
Lit un entier codé sur 4 bytes dans le fichier
Retour au byte 50
Écrit d'abord l'entier…
puis écrit les 100 bytes
Fermeture du fichier
PR1_08
24
Java / Entrées / Sorties (I/O)
Java / Entrées / Sorties (I/O)
Fichiers à accès direct [3]
Conversions types primitifs ó String
Complément
§ La classe RandomAccessFile est principalement destinée à la
manipulation de données binaires car elle n'inclut pas de méthodes
de lecture et d'écriture de chaînes de caractères assurant la
conversion au format Unicode (seuls les 8 bits de plus faible poids de
chaque caractère sont considérés).
§ Dans les opérations d'entrées/sorties avec des flux de caractères
(notamment en lecture), des conversions entre types primitifs et
String sont fréquemment nécessaires.
§ Rappel des méthodes de conversion :
Conversions
§ La méthode readLine()permet de lire une ligne de texte mais ne
fonctionne correctement que pour du texte simple (ASCII / 8 bits).
en String
de String
Type primitif
Wrapper
§ La méthode writeBytes()permet d'écrire du texte (String) mais
ne fonctionne correctement que pour du texte simple (ASCII / 8 bits).
De plus, il faut s'assurer d'ajouter les caractères de terminaison à la
fin de chaque ligne.
byte
Byte
toString(byte b)
parseByte(String s)
short
Short
toString(short s)
parseShort(String s)
int
Integer
toString(int i)
parseInt(String s)
long
Long
toString(long l)
parseLong(String s)
Remarque : Les caractères de terminaison de lignes (EOL) dépendent de
la plate-forme d'exécution :
float
Float
toString(float f)
parseFloat(String s)
double
Double
toString(double d)
parseDouble(String s)
System.getProperty("line.separator")
EIA-FR / Jacques Bapst
PR1_08
D'autres fonctions de conversion sont également disponibles dans la classe String, notamment
la méthode valueOf() qui permet de convertir en String les valeurs de tous les types primitifs.
25
EIA-FR / Jacques Bapst
Java / Entrées / Sorties (I/O)
Utilisation des fonctions de conversion
§ En Java, un programme peut recevoir des arguments lors de son
lancement (des paramètres d'exécution sur la ligne de commande).
§ Dans le programme on récupère ces paramètres dans un tableau de
chaînes de caractères (String[]) transmis à la méthode main().
§ Un exemple d'utilisation :
public class GetRuntimeParams {
public static void main(String[] args) {
int
float
double
boolean
public class Echo {
public static void main(String[] args) {
for (int i=0; i<args.length; i++) {
System.out.println(args[i]);
}
if (args.length == 0)
System.out.println("No arguments");
}
}
EIA-FR / Jacques Bapst
27
Java / Entrées / Sorties (I/O)
Arguments de la ligne de commande
prompt> java Echo hello 10 world
hello
10
world
PR1_08
prompt> java Echo
no arguments
}
PR1_08
26
}
p1
p2
p3
p4
=
=
=
=
0;
0;
0;
false;
try {
p1 = Integer.parseInt(args[0]);
p2 = Float.parseFloat(args[1]);
p3 = Double.parseDouble(args[2]);
p4 = Boolean.valueOf(args[3]).booleanValue();
}
catch (Exception e) {
System.err.println("Incorrect Runtime Parameters Types or Values");
System.err.println("Should be : int, float, double, boolean");
return;
}
. . .
. . .
EIA-FR / Jacques Bapst
PR1_08
28
Java / Classes et objets
Classes [2]
§ Une classe peut être considérée comme un moule (ou un plan)
permettant de créer des objets qui ont des propriétés similaires
mais qui ont tous leur identité propre (indépendance).
Informatique / Programmation
new
Classe
Instances
Programmation orientée objet avec Java
Objet 1
09 : Classes et objets
Objet 2
Jacques Bapst
[email protected]
Objet 3
EIA-FR / Jacques Bapst
Java / Classes et objets
3
Java / Classes et objets
Classes [1]
Propriétés des objets
§ Une classe est une collection nommée de
• de champs (ou attributs) contenant des valeurs
• de constructeurs servant à créer les objets
• de méthodes définissant des actions (opérations)
§ Un objet est principalement caractérisé par :
• une identité (son nom); doit être univoque dans le contexte
d'utilisation
• un type (la classe dont il provient, avec les classes ascendantes)
• un état (qui est défini par la valeur actuelle de ses champs);
l'état peut évoluer dans le temps (chaque objet vit sa vie)
• un comportement (qui est défini par l'ensemble de ses méthodes
publiques); ensemble des actions et des opérations possibles
§ La classe est l'élément structurel le plus fondamental de tout
programme Java (on ne peut pas écrire de code sans créer au moins
une classe).
§ Les champs et les méthodes sont collectivement nommés
membres de la classe :
§ La programmation orientée objet met les objets au cœur de la
conception des applications (contrairement à la programmation
• les champs sont les membres données
(data members)
• les méthodes sont les membres fonctions (function members)
procédurale qui centre la conception sur les traitements appliqués aux
données).
§ Chaque classe définit un nouveau type de données qui permettra
de créer (d'instancier) des objets de ce type.
§ Une application orientée objet est constituée d'un ensemble
d'objets qui communiquent en s'échangeant des messages
(par l'invocation de leurs méthodes).
§ Les objets créés sont appelés instances de la classe.
EIA-FR / Jacques Bapst
PR1_09
PR1_09
2
EIA-FR / Jacques Bapst
PR1_09
4
Java / Classes et objets
Java / Classes et objets
Déclaration de classes [1]
Déclaration des champs [1]
§ La syntaxe de base pour la déclaration d'une classe est la
suivante :
modificateurs
class
nom_de_la_classe
§ Les champs appelés aussi attributs (ou membres données)
définissent la valeur (l'état) de l'objet.
{
§ La syntaxe de déclaration des champs est proche de la
déclaration d'une variable locale :
déclaration_de_champs
déclaration_de_constructeurs
déclaration_de_méthodes
Modificateurs Type Nom_du_champ [ = Expression ] ;
}
§ Les modificateurs (liste de mots-clés) seront vus ultérieurement
(public pour l'instant).
§ Les noms de classes sont habituellement écrits avec la première
lettre en majuscule et en utilisant la notation MixedCase / CamelCase
(transition minuscules/majuscules pour séparer les éléments du nom).
§ Les modificateurs sont constitués de mots-clés qui déterminent
diverses propriétés, notamment la visibilité (public, protected,
private). Il seront étudiés dans un prochain chapitre.
§ Le type peut être soit un type primitif, un tableau ou le nom d'une
classe (rappelons que chaque classe définit un type référence).
Exemples : Random, StringReader, FileOutputStream
EIA-FR / Jacques Bapst
PR1_09
5
Java / Classes et objets
EIA-FR / Jacques Bapst
Déclaration des champs [2]
§ Exemple de déclaration de classe :
§ Une expression d'initialisation peut être mentionnée lors de la
déclaration d'un champ (= ...).
public class Point {
}
§ En l'absence d'expressions d'initialisation, les champs sont
automatiquement initialisés à leurs valeurs par défaut
(false et 0 pour les types primitifs, null pour les objets et les tableaux)
// Coordonnée x du point (champ)
// Coordonnée y du point (champ)
public Point() {
px = 0.0;
py = 0.0;
}
// Constructeur 1
public Point(double x, double y) {
px = x;
py = y;
}
// Constructeur 2
// Définition et initialisation des champs
public Point center = new Point(0, 0);
public double radius = 0.0;
public double distanceOrigin() {
return Math.sqrt(px*px + py*py);
}
// Méthode
// Suite de la déclaration de la classe Cercle
...
...
EIA-FR / Jacques Bapst
7
Java / Classes et objets
Déclaration de classes [2]
public double px;
public double py;
PR1_09
public class Circle {
}
PR1_09
6
EIA-FR / Jacques Bapst
PR1_09
8
Java / Classes et objets
Java / Classes et objets
Méthodes
Constructeurs [1]
§ Les méthodes ont déjà été étudiées dans un chapitre précédent.
§ Un constructeur est une sorte de méthode qui sera invoquée
lors de la création d'un objet de cette classe (opérateur new).
§ Elles ne sont pas forcément déclarées avec le modificateur static
(c'est même plutôt l'exception en programmation objet).
Un prochain chapitre sera consacré à approfondir les notions de
champs/méthodes statiques et non-statiques.
§ Un constructeur doit porter le nom de la classe et ne doit
pas comporter de type de retour dans sa déclaration (même
pas void).
§ Les méthodes ont accès aux champs de la classe dans laquelle
elles sont déclarées. Ces champs sont accessibles par leurs noms
simples ou en utilisant le préfixe this (explication de ce mot réservé
dans les pages suivantes).
§ Le but du constructeur est d'initialiser l'objet (notamment la
valeur de ses champs).
§ Un constructeur retourne implicitement une référence à une
instance de la classe (objet).
§ Les méthodes peuvent invoquer d'autres méthodes définies dans la
même classe en utilisant leur nom simple ou en utilisant le préfixe
this (comme pour les champs).
§ Si aucun constructeur n'est défini dans une classe, Java fournit
un constructeur par défaut, sans argument, et qui se charge
uniquement de créer les champs et de leur attribuer une valeur
initiale (valeur par défaut ou valeur de l'expression d'initialisation).
EIA-FR / Jacques Bapst
PR1_09
§ Les constructeurs ne sont pas des méthodes à strictement parler
même si, par beaucoup d'aspects, ils leur ressemblent.
9
Java / Classes et objets
Déclaration et création d'objets
§ La classe Point permet de déclarer des objets de ce type :
§ Comme les méthodes, les constructeurs peuvent être surchargés
(en suivant les même règles).
Point p1;
§ Pour créer un objet on utilise l'opérateur new suivi du nom de la
classe et d'une liste facultative d'arguments entre parenthèses.
§ Dans la déclaration de la classe Point, le premier constructeur
aurait pu être écrit ainsi :
EIA-FR / Jacques Bapst
// Déclaration d'un objet de type Point
§ La déclaration ne crée pas un objet mais uniquement une
référence vers un objet du type mentionné (comme pour les
tableaux).
p1
§ Lorsqu'une classe possède des constructeurs multiples
(surchargés), il est possible, dans le corps d'un constructeur,
d'invoquer un autre constructeur, un utilisant la syntaxe spéciale :
this(expr1, expr2, ...)
Restriction importante :
11
PR1_09
Java / Classes et objets
Constructeurs [2]
public Point() {
this(0.0, 0.0);
}
EIA-FR / Jacques Bapst
new
// Constructeur 1
// Invocation du Constructeur 2
nom_de_la_classe (expr1, expr2 , ...
new Point(1.2, 3.4)
1.2
px
3.4
py
§ L'opérateur new fait appel à l'un des constructeurs de la classe
en fonction du profil des paramètres transmis (constructeur par
défaut ou l'un des constructeurs définis explicitement dans la classe).
L'appel à this(...) doit apparaître comme
première instruction dans un constructeur.
PR1_09
)
10
EIA-FR / Jacques Bapst
PR1_09
12
Java / Classes et objets
Java / Classes et objets
Création d'objets
Utilisation des objets
§ La classe Point déclarée précédemment permet de déclarer et de
créer des objets de ce type :
§ L'accès aux membres des objets s'effectue en utilisant l'opérateur
point (.) selon la syntaxe suivante :
Point p1;
// Déclaration d'un objet de type Point
p1 = new Point();
// Création d'un objet et assignation
// de la référence à p1
Point p2 = new Point();
// Déclaration de p2, création d'un
// objet Point et assignation de la
// référence à p2
Point p3 = new Point(2.0, 4.5);
Nom_de_l'objet.Nom_du_membre
§ Le membre pouvant être soit un champ soit une méthode :
Point p1 = new Point(1.0, 2.0); // Déclare et crée un objet p1
// Idem, mais utilisation du deuxième
// constructeur pour créer l'objet
double vx, vy, d;
// Lit un champ de l'objet p1
§ Les objets, comme les tableaux, sont des types référence.
vx
= p1.px;
vy
= p1.py;
p1.px = p1.px + 1.5;
§ p1, p2 et p3 ne contiennent donc pas les objets mais sont des
références vers les zones mémoires contenant les objets.
d = p1.distanceOrigin();
// Exécute une méthode de p1
EIA-FR / Jacques Bapst
PR1_09
13
Java / Classes et objets
EIA-FR / Jacques Bapst
PR1_09
15
Java / Classes et objets
Représentation en mémoire
Référence
Complément
// Modifie la valeur du champ
Notion d'objet [1]
§ Objet
Objet référencé
p1 = new Point(2.5, 4.2);
p1
1205
1206
1207
1208
1209
2320
2320
2321
2322
2323
2324
Point
2.5
4.2
Nom classe
Champ p1.px
Champ p1.py
Création de l'espace mémoire pour
contenir l'objet et initialisation des
champs (constructeur)
: Entité typée et nommée qui possède des attributs et
des méthodes
§ Attribut : Case mémoire typée et nommée
§ Méthode : Procédure ou fonction nommée qui a accès aux
attributs de l'objet
§ Pour accéder aux composants (membres) d'un objet il faut :
• détenir une variable qui référence cet objet
Notation abstraite
Référence
p1 = new Point(2.5, 4.2);
2.5
px
4.2
py
p1
EIA-FR / Jacques Bapst
• connaître le nom de l'attribut ou de la méthode
Objet référencé
• utiliser l'opérateur "."
• utilisation comme une variable, resp. une procédure / fonction
Notation
à utiliser
PR1_09
14
EIA-FR / Jacques Bapst
PR1_09
16
Java / Classes et objets
Java / Classes et objets
Notion d'alias
Notion d'objet [2]
§ Exemple :
• Type d'objet Car
int
float
• Attributs
• Méthodes
year
speed
void
fillTank
(int liters)
double breakDownRisk(int km)
Type primitif
Objet / Tableau
Affectation
a = b
Copie de la valeur
Copie de la référence
L'objet n'est pas modifié
Comparaison
a == b
Test sur la valeur
Test sur la référence,
pas sur le contenu de l'objet !
Passage de la valeur
(copie locale)
Passage de la référence (copie)
L'objet risque d'être modifié !
Passage en paramètre
p(a)
§ Type primitif
Car c = new Car();
c
c.year = 1999;
System.out.println(c.speed);
c.fillTank(30);
System.out.println(c.breakDownRisk(50));
1999
year
80.3
speed
§ Objet / Tableau : accès à la zone mémoire possible par plusieurs variables
Car myCar
Car otherCar
fillTank()
breakDownRisk()
System.out.println(myCar.year);
EIA-FR / Jacques Bapst
PR1_09
17
Java / Classes et objets
int
Engine
Type d'objet
Engine
Attributs
char
int
EIA-FR / Jacques Bapst
!!!
EIA-FR / Jacques Bapst
PR1_09
19
§ Le mot clé this est utilisé pour référencer l'objet à l'intérieur
duquel le code est exécuté.
Pour la déclaration de variables locales
Pour la déclaration d'attributs d'un objet
Comme paramètres de méthodes
Comme résultat d'une fonction
Attributs
2014
Référence à l'objet courant : this
§ Les types référence sont de vrais types Java qui peuvent être
utilisés :
Car
//
Java / Classes et objets
Notion d'objet [3]
Type d'objet
= new Car();
= new Car();
myCar.year
= 1999;
otherCar
= myCar;
otherCar.year = 2014;
Généralement, les méthodes ne sont pas
mentionnées dans la représentation de
l'état de la mémoire.
•
•
•
•
: accès à la zone mémoire par une seule variable
year
motor
type
power
§ On peut considérer que l'objet this est implicitement passé en
référence lors de l'invocation de chaque méthode d'instance :
Point p1 = new Point(1.0, 2.0);
double d = p1.distanceOrigin();
1999
myCar
Dans l'exemple ci-dessus, l'objet p1 est implicitement passé en
paramètre (invisible) à la méthode distanceOrigin().
A l'intérieur du corps de la méthode distanceOrigin() on peut,
si nécessaire, utiliser le mot-clé this pour référencer l'objet sur
lequel la méthode a été invoquée (p1 dans cet exemple).
year
motor
'K'
type
86
power
PR1_09
Attention : Il ne faut pas confondre this utilisé pour référencer l'objet
courant avec la forme this() qui est utilisée pour invoquer
un constructeur depuis un autre constructeur.
18
EIA-FR / Jacques Bapst
PR1_09
20
Java / Classes et objets
Classe : Notation UML
§ Dans le langage de modélisation UML (Unified Modeling Language),
les classes sont représentées graphiquement sous la forme de
rectangles comprenant le nom de la classe et éventuellement le
nom des champs, des constructeurs et des méthodes.
§ Différents niveaux de détails sont possibles :
Point
Point
distanceOrigin()
Méthodes Champs
px
py
Point
+ px : double
+ py : double
+ Point(x : double, y : double)
+ distanceOrigin() : double
Indicateurs de visibilité :
+ : public
EIA-FR / Jacques Bapst
- : private
# : protected
PR1_09
21
Java / Classes et objets
En bref, écrire une classe c'est…
§ Choisir un nom pour la classe
• Intégrer cette classe dans un paquetage
§ Écrire la spécification (déclarer la partie publique)
• Signature des méthodes avec les exceptions prévues
• Explication de l'effet attendu (rôle des paramètres, valeur de retour,
effet sur les données, pré- et post-conditions)
§ Écrire une implémentation :
• Définition des attributs (choix des structures de données)
• Conception du corps des méthodes (choix des algorithmes)
• Codage proprement dit (identificateur, flux d'instructions, lisibilité,
méthodes privées)
§ Tester le bon fonctionnement
§ Éventuellement
• Documenter la classe avec /** … */ (Javadoc)
• Affiner, optimiser, …
EIA-FR / Jacques Bapst
PR1_09
22
Java / Packages, contrôle d'accès, encapsulation
Paquetages
Informatique / Programmation
§ Un paquetage (Package) est une collection nommée de
classes et/ou d'interfaces. Un paquetage peut comprendre des
sous-paquetages.
§ Les paquetages permettent de grouper des classes apparentées
et de définir un espace de désignation (Namespace) pour les
classes qu'il contient.
Programmation orientée objet avec Java
§ Les paquetages servent également à gérer les droits d'accès
(visibilité) des classes les unes par rapport aux autres.
10 : Packages / Contrôle d'accès / Encapsulation
§ Les paquetages sont organisés de manière hiérarchique
(structure arborescente avec racines multiples).
§ Dans le nom des paquetages, le point ('.') est utilisé comme
séparateur entre les différents niveaux hiérarchiques.
Jacques Bapst
[email protected]
§ Exemple :
java.lang.String :
La classe String se trouve dans le sous-paquetage
lang du paquetage java
EIA-FR / Jacques Bapst
Java / Packages, contrôle d'accès, encapsulation
3
Java / Packages, contrôle d'accès, encapsulation
Unités de compilation
Déclaration de paquetage [1]
§ Le mot clé package est utilisé pour indiquer le paquetage auquel
appartiennent la ou les classes de l'unité de compilation.
§ Un programme Java est généralement constitué d'un ensemble
de classes.
§ Le code source de chaque classe publique doit être enregistré
dans un fichier séparé portant le nom de la classe avec l'extension
".java".
Un tel fichier constitue une unité de compilation.
§ Le résultat de la compilation (Bytecode) est enregistré dans un
fichier portant le nom de la classe avec l'extension ".class".
package
§ Exemple :
;
package ch.eiafr.tic;
public class Point {
...
}
• La classe Point déclarée précédemment doit être enregistrée dans un
fichier nommé "Point.java"
§ La classe Point fait partie du paquetage ch.eiafr.tic
• Après la compilation, un nouveau fichier "Point.class" sera créé, il
contiendra le Bytecode correspondant à la classe Point
PR1_10
Nom_du_paquetage
§ Cette pseudo-instruction, si elle est utilisée, doit être la première
(hormis les commentaires) de l'unité de compilation (fichier source).
§ Exemple :
EIA-FR / Jacques Bapst
PR1_10
§ Le nom complet de la classe est "ch.eiafr.tic.Point"
2
EIA-FR / Jacques Bapst
PR1_10
4
Java / Packages, contrôle d'accès, encapsulation
Java / Packages, contrôle d'accès, encapsulation
Déclaration de paquetage [2]
Importation de paquetage [2]
§ Si aucune instruction package n'apparaît dans un fichier source,
(ce qui est déconseillé ) les classes définies dans cette unité de
compilation seront attribuées à un paquetage par défaut (qui est
anonyme).
§ L'instruction import doit être placée au début de l'unité de
compilation, juste après l'instruction package (s'il y en a une).
§ L'instruction import peut être répétée à volonté pour importer
plusieurs classes et/ou plusieurs paquetages.
§ Les noms des paquetages sont habituellement écrits en utilisant
uniquement des minuscules (convention de codage ).
§ L'importation d'un paquetage entier (....*) ne rend pas visible
le contenu des éventuels sous-paquetages. Si nécessaire,
les sous-paquetages doivent être importés explicitement.
§ Pour faciliter l'échange de code Java (librairies publiques), il est
utile d'avoir un espace de désignation globalement univoque
(pour éviter les conflits dans les noms de classes).
§ En cas de conflit (importation de paquetages contenant des classes
portant le même nom), le compilateur imposera l'utilisation du nom
complet pour accéder aux classes homonymes.
§ C'est pour cela qu'il est recommandé de créer l'arborescence des
paquetages en utilisant comme racine, les noms de domaines
internet (en inversant les éléments de l' URL, tout en respectant la
syntaxe des identificateurs Java !).
Exemple :
Nom de domaine
Racine des paquetages
§ Le paquetage java.lang étant considéré comme fondamental, il
est implicitement importé et l'on peut donc utiliser ses classes
par leurs noms simples (par exemple : String, Math, System, ...)
sans avoir à les importer.
: eia-fr.ch
: ch.eiafr
EIA-FR / Jacques Bapst
PR1_10
EIA-FR / Jacques Bapst
5
Java / Packages, contrôle d'accès, encapsulation
Importation statique
§ Par défaut, une classe d'un paquetage p peut faire référence à
toute autre classe de p par son nom simple (le nom de la classe
uniquement, par exemple Point).
§ Afin d'alléger l'écriture, on peut "importer" les classes d'un paquetage
externe en utilisant l'instruction import.
§ Il existe deux formes :
• Importation d'une classe individuelle : import ch.eiafr.tic.Line;
: import ch.eiafr.tic.*;
Complément
§ Depuis la version 1.5 du langage, il est possible d'importer
sélectivement ou globalement les membres statiques d'une
classe en ajoutant le mot-clé static à l'instruction import
(les membres statiques seront vus en détail au chapitre suivant).
§ Pour référencer une classe d'un paquetage différent de celui
dans lequel on se trouve, il faut utiliser son nom complet
(paquetage + classe, par exemple ch.eiafr.tic.Line).
§ Cette importation statique permet, dans certains cas, d'alléger
l'écriture en évitant de devoir préfixer les champs et les méthodes
statiques avec le nom du package et/ou de la classe.
§ Par exemple :
import static java.lang.Math.max;
importe la méthode statique max() qui pourra donc être invoquée
sans préfixe :
r = max(v1, v2);
§ Pour importer tous les membres statiques de la classe Math :
§ L'instruction import rend accessible, par leurs noms simples,
les classes externes mentionnées.
EIA-FR / Jacques Bapst
7
Java / Packages, contrôle d'accès, encapsulation
Importation de paquetage [1]
• Importation de toutes les classes
contenues dans un paquetage
PR1_10
PR1_10
import static java.lang.Math.*;
a = PI * pow(r, 2);
6
EIA-FR / Jacques Bapst
PR1_10
8
Java / Packages, contrôle d'accès, encapsulation
Java / Packages, contrôle d'accès, encapsulation
Structure des unités de compilation
Paquetages et unités de compilation [1]
§ La hiérarchie des répertoires du disque dans lesquels sont
enregistrés les fichiers des classes (.class) doit correspondre
à la hiérarchie des paquetages.
Paquetages
package ch.eiafr.tic;
public class Point {...}
package ch.eiafr.tic.tools;
public class Complex {...}
public class Graph {...}
package ch.eiafr.tic.test;
§ En résumé, les unités de compilation (fichiers .java") doivent
respecter la structure suivante :
Répertoires / Fichiers
C:
|
+-ClassesJava
|
+-ch
|
+-eiafr
|
+-tic
|
+-test
|
+-tools
public class TestPoint {...}
EIA-FR / Jacques Bapst
package ...;
• zéro, une ou plusieurs instructions import
import ...;
import ...;
import ...;
• une ou plusieurs définitions de classes (class),
d'interfaces ou de classes-internes
(mais une seule classe ou interface publique
au premier niveau)
Racine des paquetages
Point.class
TestPoint.class
Complex.class
Graph.class
PR1_10
• (zéro ou) une instruction package
9
Java / Packages, contrôle d'accès, encapsulation
public class ... {
...
}
§ Ces éléments (package, import, class) peuvent naturellement
être entourés de commentaires, mais ils doivent impérativement
apparaître dans l'ordre mentionné ci-dessus.
EIA-FR / Jacques Bapst
PR1_10
Java / Packages, contrôle d'accès, encapsulation
Librairie de classes Java
Paquetages et unités de compilation [2]
§ La hiérarchie des fichiers contenant les classes constitue un sousarbre qui peut être placé n'importe où dans l'arborescence générale
du disque.
§ La plate-forme Java comprend une vaste collection de classes
prédéfinies qui peuvent être utilisées indépendamment de
l'environnement d'exécution des applications.
§ Le paramètre (ou la variable d'environnement) classpath indique
à la machine virtuelle Java, la liste des répertoires (racines) dans
lesquels se trouvent les classes.
§ Cette librairie de classes est organisée en paquetages (et
sous-paquetages) qui rassemblent, par domaine, des classes
apparentées.
java -classpath .;C:\ClassesJava;G:\Info\Lib ...
§ L'arborescence des paquetages de la plate-forme Java possède
deux racines principales java et javax.
§ A partir de ces racines (points d'entrée), la machine virtuelle
complète le chemin d'accès en y ajoutant les sous-répertoires
définis par l'arborescence des paquetages.
§ Les pages qui suivent donnent un aperçu succinct (quelques
paquetages importants) de la plate-forme Java.
Conseil : Inutile de réinventer la roue. Avant de coder une fonction
particulière, il faut s'assurer qu'elle n'est pas disponible
dans la bibliothèque des classes standard.
Remarque : L'ensemble des fichiers .class peut également être enregistré
dans un seul fichier .jar qui contient toutes les classes et leur
arborescence sous forme éventuellement comprimée (format ZIP).
EIA-FR / Jacques Bapst
11
PR1_10
10
EIA-FR / Jacques Bapst
PR1_10
12
Java / Packages, contrôle d'accès, encapsulation
Java / Packages, contrôle d'accès, encapsulation
Librairie de classes Java [3]
java.lang
Le noyau des classes du langage, comprenant notamment
String, Math, System, Thread et Exception.
Ce package est implicitement importé.
java.io
Classes et interfaces d'entrée/sorties. Bien que certaines
des classes de ce paquetage soient conçues pour travailler
directement avec les fichiers, la plupart d'entre-elles permet
de travailler avec des flux d'octets ou des flux de caractères.
java.math
Petit paquetage qui contient des classes destinées à
l'arithmétique entière de précision arbitraire et à
l'arithmétique décimale.
javax.swing
Grand paquetage (comportant de nombreux souspaquetages) destiné à étendre AWT pour la création
d'interfaces utilisateur graphiques (GUI) sophistiquées.
Introduit de nouveaux composants graphiques avec des
propriétés beaucoup plus étendues qu'AWT.
javax.swing.event
Complète et améliore java.awt.event avec des classes
spécialisées pour les composants Swing.
§ Une description de l'ensemble des classes (et interfaces) contenues dans
ces paquetages accompagne le JDK (Java Development Kit).
La documentation est à télécharger séparément.
java.net
Classes et interfaces destinées à l'interconnexion avec
d'autres systèmes (réseau).
java.security
Classes et interfaces de contrôle d'accès et
d'authentification. Plusieurs sous-paquetages.
§ Elle peut être consultée en ligne sur le site d'Oracle :
http://docs.oracle.com/javase/8/docs/api/
java.util
Diverses classes utilitaires y compris un cadre de collections
puissant, à utiliser avec les collections d'objets
§ Les environnements de développement (Eclipse, NetBeans, …) permettent
généralement également de consulter la description des API de la plateforme Java (voir documentation correspondante).
EIA-FR / Jacques Bapst
PR1_10
13
Java / Packages, contrôle d'accès, encapsulation
PR1_10
15
Contrôle d'accès aux membres
java.applet
Définit la classe Applet qui est la super-classe de toutes les
applets.
javax.accessibility
Ensemble de classes et d'interfaces permettant la
réalisation d'applications adaptées à des personnes
handicapées (par exemple mal-voyants)
java.awt
Définit le cadre de l'interface utilisateur graphique de base
AWT (Abstract Windowing Toolkit). Contient également les
classes permettant de gérer des graphiques 2D.
java.awt.event
Définit les classes et les interfaces utilisées pour la gestion
des événements en AWT et Swing.
java.awt.image
Ensemble de classes et d'interfaces servant à manipuler les
images.
java.awt.print
Ensemble de classes et d'interfaces destinées à
l'impression de documents.
EIA-FR / Jacques Bapst
EIA-FR / Jacques Bapst
Java / Packages, contrôle d'accès, encapsulation
Librairie de classes Java [2]
Complément
Complément
Complément
Librairie de classes Java [1]
PR1_10
§ Tous les champs et toutes les méthodes d'une classe peuvent
être utilisés dans le corps de la classe elle-même en utilisant
leurs noms simples.
§ Cependant, le langage Java permet de spécifier des restrictions
d'accès aux membres d'une classe (champs et méthodes) en
dehors de cette classe (appelée classe de définition ou classe de
déclaration).
§ Le contrôle d'accès aux membres s'effectue à l'aide de
différents mots-clés qui peuvent précéder la déclaration des
champs et des méthodes (ces mots-clés font partie d'un groupe de
mots réservés appelés modificateurs).
§ Le mode d'accès par défaut (si l'on n'indique aucun mot-clé de
contrôle d'accès dans la déclaration) est appelé "package" ou parfois
"friendly" (mais ces termes ne peuvent pas être utilisés comme
modificateurs dans le code).
14
EIA-FR / Jacques Bapst
PR1_10
16
Java / Packages, contrôle d'accès, encapsulation
Java / Packages, contrôle d'accès, encapsulation
Modificateurs d'accès [1]
Modificateur d'accès private
§ Si, dans une classe A, on déclare un objet k de type A (ou si une
méthode de la classe A reçoit en paramètre un objet k de type A)
alors les membres privés de l'objet k sont accessibles à l'intérieur
de la classe A.
§ Les modificateurs qui contrôlent l'accès aux membres ( champs ou
méthodes) sont les suivants :
Modificateur
Description des droits d'accès sur le membre
public
Accessible à toutes les classes de tous les paquetages
protected
Accessible aux classes dérivées (sous-classes) ainsi
qu'aux classes du même paquetage
Sera décrit plus en détail dans le cadre de l'héritage
Aucun
(ð package)
Accessible à toutes les classes du même paquetage
private
Accessible seulement aux autres membres de la
même classe (classe de définition)
§ Autrement dit, dans une classe A, on peut accéder aux membres
privés de tous les objets de type A (pas seulement ceux de this).
public class A {
...
private int x;
private A
c;
...
public void m1(A k) {
k.x = this.x + 2;
System.out.println(k.x);
}
§ Le modificateur public peut également être utilisé dans la déclaration
des classes. Il indique que la classe est accessible partout où le
paquetage est accessible (par import ...).
Sans lui, la classe n'est accessible qu'au sein de son paquetage.
EIA-FR / Jacques Bapst
PR1_10
...
public void m2() {
x += c.x;
}
...
17
EIA-FR / Jacques Bapst
PR1_10
19
Java / Packages, contrôle d'accès, encapsulation
Modificateurs d'accès [2]
Encapsulation [1]
§ L'une des techniques essentielles de la programmation orientée
objet est l'encapsulation.
§ Les règles d'accès aux membres peuvent également être
présentées sous la forme suivante :
§ L'encapsulation consiste à masquer les données au sein des
classes et à manipuler leur contenu qu'au moyen de
méthodes publiques.
public protected package private
Classe de définition
Oui
Oui
Oui
Oui
Classe du même paquetage
Oui
Oui
Oui
Non
Sous-classe dans un paquetage
différent
Oui
Oui
Non
Non
Classe (qui n'est pas une
sous-classe) dans un paquetage
différent
Oui
§ La mise en place du mécanisme d'encapsulation s'effectue en
utilisant judicieusement les contrôles d'accès aux membres
des classes.
§ Avantages de l'encapsulation :
Non
Non
Non
• Masquage des détails de l'implémentation (qui peut être changée
sans conséquences pour les utilisateurs externes)
• Protection de la classe contre des utilisations erronées (contrôles de
cohérence dans les méthodes)
• Simplification de l'API (les champs et les méthodes internes sont
cachés)
Par défaut
EIA-FR / Jacques Bapst
// c.x est accessible
}
Java / Packages, contrôle d'accès, encapsulation
Accessible à :
// k.x est accessible
PR1_10
18
EIA-FR / Jacques Bapst
PR1_10
20
Java / Packages, contrôle d'accès, encapsulation
Encapsulation [2]
§ En règle générale, il est recommandé de masquer les champs
en les déclarant private et - seulement si nécessaire - de
définir des méthodes publiques pour accéder à ces champs
(ces méthodes appelées accesseurs/mutateurs ou getters/setters sont
généralement nommées getxxx (), isxxx() et setxxx()).
§ Version encapsulée de la classe Point :
public class Point {
private double px;
private double py;
}
// Coordonnée x du point (champ)
// Coordonnée y du point (champ)
public Point() {...}
public Point(double x, double y) {...}
// Constructeur 1
// Constructeur 2
public double getPx() {return px;}
public double getPy() {return py;}
// Get px
// Get py
public void setPx(double x) {px = x;}
public void setPy(double y) {py = y;}
// Set px
// Set py
(nécessaire ?)
(nécessaire ?)
public double distanceOrigin() {...}
EIA-FR / Jacques Bapst
PR1_10
21
Java / Membres statiques, initialiseurs, finaliseurs, wrappers
Membres de classe [1]
Informatique / Programmation
§ On peut également créer des membres associés à la classe qui
sont appelés membres de classe ou membres statiques.
§ Pour rendre un membre statique, on utilise le mot-clé (modificateur)
static devant la déclaration du champ ou de la méthode :
public class Point {
Programmation orientée objet avec Java
public
public
public
public static
11 : Membres statiques, initialiseurs, wrappers …
double
double
int
int
px;
py;
pNr;
nextNr = 1;
//
//
//
//
public Point(double x, double y) {
Champ
Champ
Champ
Champ
d'instance
d'instance
d'instance
statique
// Constructeur
. . .
pNr = nextNr++;
Jacques Bapst
}
public double distanceOrigin() {...}
[email protected]
}
// Méthode d'instance
// Méthode statique
public static double distance(Point p1, Point p2) {...}
EIA-FR / Jacques Bapst
Java / Membres statiques, initialiseurs, finaliseurs, wrappers
PR1_11
Java / Membres statiques, initialiseurs, finaliseurs, wrappers
Membres d'instance
Membres de classe [2]
§ Les membres de classe ne sont pas associés aux instances (objets)
mais seulement à la classe. Ils sont accessibles par toutes les
instances de la classe (ils sont partagés par toutes les instances).
§ Par défaut, lors de la création d'un objet (instanciation d'une classe
avec l'opérateur new), les membres (champs et méthodes) sont
associés à chacune des instances de la classe.
On les appelle membres d'instance.
Classe
Classe
new
3
new
Instances
Instances
Point : p1
Point
Point : p1
Point
px
py
distanceOrigin()
px
py
pNr
nextNr
px = 1.0
py = 2.0
distanceOrigin()
Point : p2
px = 3.0
py = 1.5
distanceOrigin()
distance(Point, Point)
PR1_11
distanceOrigin()
Point : p2
px = 3.0
py = 1.5
pNr = 2
distanceOrigin()
distanceOrigin()
EIA-FR / Jacques Bapst
px = 1.0
py = 2.0
pNr = 1
2
EIA-FR / Jacques Bapst
PR1_11
4
Java / Membres statiques, initialiseurs, finaliseurs, wrappers
Java / Membres statiques, initialiseurs, finaliseurs, wrappers
Membres de classe [3]
Importation statique
§ Il est possible d'importer sélectivement ou globalement les
membres statiques d'une classe en ajoutant le mot-clé static
à l'instruction import.
§ On peut donc déclarer :
- des champs statiques (ou champs de classe)
- des méthodes statiques (ou méthodes de classe)
Complément
§ Les champs statiques sont enregistrés au niveau de la classe
et ils peuvent être accédés et manipulés par toutes les instances
(objets) de cette classe.
§ Indépendamment du nombre d'objets créés, il n'existe qu'un
seul exemplaire des données associées aux champs statiques
(contrairement aux champs d'instance dont il existe un exemplaire pour
chaque objet créé).
PR1_11
§ Par exemple :
import static java.lang.Math.max;
importe la méthode statique max() qui pourra donc être invoquée
sans préfixe :
r = max(v1, v2);
§ Pour importer tous les membres statiques de la classe Math :
§ On peut considérer les champs statiques comme étant des
variables globales partagées par toutes les instances.
Il faut donc les utiliser avec précaution et parcimonie afin d'éviter
des couplages inutiles (ou même dangereux) entre objets.
EIA-FR / Jacques Bapst
§ Cette importation statique permet, dans certains cas, d'alléger
l'écriture en évitant de devoir préfixer les champs et les méthodes
statiques avec le nom du package et/ou de la classe.
import static java.lang.Math.*;
a = PI * pow(r, 2);
5
Java / Membres statiques, initialiseurs, finaliseurs, wrappers
EIA-FR / Jacques Bapst
PR1_11
Java / Membres statiques, initialiseurs, finaliseurs, wrappers
Représentation en mémoire
Membres de classe [4]
§ Les méthodes statiques sont liées à une classe et non pas à
une instance (objet) de la classe.
§ Les champs statiques existent et sont accessibles même si l'on
n'a pas créé d'objets.
§ Dans une méthode statique, on ne peut pas faire référence à
une méthode d'instance sans créer d'objet, car les méthodes
statiques ne s'exécutent pas dans le contexte d'un objet
(autrement dit, pour les méthodes statiques, il n'existe pas de référence
this).
§ On les représentera donc dans une zone mémoire liée à la classe
et commune à toutes les instances de cette classe.
p1 = new Point(2.5, 4.2);
p2 = new Point(5.0, 6.0);
§ Pour accéder à un membre statique d'une classe en dehors de
cette classe, il faut préfixer le nom du membre (champ ou
méthode) avec le nom de la classe (ou utiliser import static…).
Point
Point
int
double
double
p1
p2
n
d1
d2
=
=
=
=
=
new Point(1.0, 2.0);
new Point(2.0, 3.0);
Point.nextNr;
Point.distance(p1, p2);
p1.distanceOrigine();
EIA-FR / Jacques Bapst
7
= Point.nextNr;
n
= p1.nextNr;
Bien que déconseillée, cette notation
est acceptée par le langage.
Le compilateur la remplacera par
n = Point.nextNr;
// Champ statique
// Méthode statique
// Méthode d'instance
PR1_11
n
Le champ statique nextNr est associé à
la classe Point et est commun à toutes
ses instances
6
EIA-FR / Jacques Bapst
p1
p2
Point
2.5
px
4.2
py
1
pNr
5.0
px
6.0
py
2
pNr
3
nextNr
PR1_11
8
Java / Membres statiques, initialiseurs, finaliseurs, wrappers
Java / Membres statiques, initialiseurs, finaliseurs, wrappers
Modificateur final
Initialiseur statique
§ Le modificateur final peut être utilisé lors de la déclaration de
variables locales, de paramètres de méthodes et de champs.
§ Exemple d'initialisation statique :
//-------------------------------------------------------// Calcule à l'avance et mémorise certaines valeurs
// trigonométriques dans un tableau
//-------------------------------------------------------public class Sinusoid {
§ Il indique que la valeur de la variable ou du champ ne peut plus
être modifiée après l'affectation initiale.
Cela revient donc à déclarer des constantes.
private static int
nbPoints = 500;
public static double[] valSine = new double[nbPoints];
§ Il est très fréquent de déclarer les constantes générales comme
champs statiques au niveau de la classe et de les déclarer public.
// Initialisation du tableau valSine
static {
double x = 0.0;
double dx = (Math.PI/2)/(nbPoints-1);
Exemple : public static final double PI = 3.141592653589793;
§ Les champs déclarés constants (static final) sont habituellement
écrits en majuscules et utilisent le caractère sous-ligné '_' comme
séparateur.
for(int i=0; i<nbPoints; i++, x+=dx) {
valSine[i] = Math.sin(x);
}
Exemple : private static final double FREQUENCY_MAX = 3.5E9;
}
...
§ Pour les classes et les méthodes, une autre utilisation du mot-clé
final sera vue dans le cadre de l'héritage.
EIA-FR / Jacques Bapst
PR1_11
}
EIA-FR / Jacques Bapst
9
Java / Membres statiques, initialiseurs, finaliseurs, wrappers
11
Java / Membres statiques, initialiseurs, finaliseurs, wrappers
Initialisation de classes
Initialiseur d'instance [1]
§ Le langage Java permet d'écrire du code d'initialisation de
classe qui sera exécuté lors de l'élaboration de la classe (en
même temps que l'initialisation des champs statiques).
§ Les classes peuvent également posséder des initialiseurs
d'instance.
§ Un initialiseur d'instance initialise un objet (contrairement à
l'initialiseur statique qui initialise une classe)
Complément
§ Ce code appelé initialiseur statique est simplement constitué
d'un bloc d'instructions (entre accolades) précédé du mot-clé
static.
§ Une classe peut posséder un nombre quelconque d'initialiseurs
statiques qui peuvent être placés partout où une déclaration de
champ ou une déclaration de méthode est permise (ils seront
exécutés dans ordre d'écriture du code dans le fichier source ).
§ Les initialiseurs statiques peuvent être considérés comme des
méthodes statiques anonymes.
PR1_11
§ Un initialiseur d'instance est constitué d'un bloc d'instructions
entre accolades (il peut y en avoir plusieurs dans une classe, ils seront
exécutés dans l'ordre d'écriture du code dans le fichier source).
§ Les initialiseurs d'instance sont exécutés après le constructeur de
la classe parente et avant le constructeur de la classe dans laquelle
ils sont déclarés.
Conseil : Il est généralement préférable d'effectuer les initialisations
de l'objet dans le constructeur de la classe.
§ Les restrictions définies pour les méthodes statiques s'appliquent
également aux instructions des initialiseurs statiques.
EIA-FR / Jacques Bapst
PR1_11
10
EIA-FR / Jacques Bapst
PR1_11
12
Java / Membres statiques, initialiseurs, finaliseurs, wrappers
Java / Membres statiques, initialiseurs, finaliseurs, wrappers
Initialiseur d'instance [2]
Wrappers [1]
§ Exemple d'initialiseur d'instance :
§ En Java, pour des raisons d'efficacité, les types primitifs ne sont
pas des objets.
Complément
public class ... {
...
private static int
dim
= 1000;
private
int[] intArr = new int[dim];
}
§ Dans certaines circonstances, il peut être utile de pouvoir traiter
les types primitifs comme des objets (par exemple pour pouvoir
les enregistrer dans des structures de données abstraites de type
liste, pile, arbre, … ne manipulant généralement que des objets).
// intArr initialization
{
for(int i=0; i<dim; i++) {
intArr[i] = i;
}
}
...
§ Ainsi, il existe pour chaque type primitif, une classe Wrapper
(classe d'emballage, classe enveloppe) qui permet de convertir
(d'emballer) une variable (ou une valeur littérale) de type primitif en
un objet correspondant (une instance d'une des classes d'emballage).
§ Les classes Wrapper sont déclarées dans le paquetage java.lang
(et sont donc accessibles sans importation explicite).
§ Les classes Wrapper disposent d'un certain nombre de constantes
et de méthodes (statiques et non-statiques) permettant d'effectuer
diverses conversions.
EIA-FR / Jacques Bapst
PR1_11
13
Java / Membres statiques, initialiseurs, finaliseurs, wrappers
EIA-FR / Jacques Bapst
Wrappers [2]
§ Un finaliseur représente l'opposé d'un constructeur et exécute du
code de finalisation de l'objet.
§ Liste des classes d'emballage (Wrappers) :
§ Le ramasse-miettes (garbage-collector) se charge de récupérer
automatiquement l'espace mémoire utilisé par les objets ( dès que ces
derniers ne sont plus référencés). Le programmeur n'a pas à se soucier
de cet aspect.
Complément
15
Java / Membres statiques, initialiseurs, finaliseurs, wrappers
Finaliseur d'objet : finalize
§ Cependant, si l'objet contient d'autres types de ressources ( fichiers
ouverts, connexions réseau, transactions dans une base de données, etc.)
il peut être nécessaire d'écrire du code de finalisation qui devra
s'exécuter avant que l'objet disparaisse.
§ Un finaliseur est une méthode d'instance (héritée de Object)
- dont le nom est finalize()
- qui ne possède aucun paramètre
- qui ne retourne aucune valeur (void)
PR1_11
Type primitif
Classe Wrapper
byte
Byte
short
Short
int
Integer
long
Long
float
Float
double
Double
char
Character
boolean
Boolean
(Et non pas Int !)
(Et non pas Char !)
§ A deux exceptions près, le nom de la classe Wrapper correspond
à celui du type primitif avec une majuscule initiale.
§ La méthode finalize() (si elle a été définie) sera invoquée
automatiquement par la machine virtuelle avant que le ramassemiettes ne détruise l'objet.
EIA-FR / Jacques Bapst
PR1_11
§ Les classes Wrapper créent des objets immuables !
14
EIA-FR / Jacques Bapst
PR1_11
16
Java / Membres statiques, initialiseurs, finaliseurs, wrappers
Wrappers [3]
§ Exemples d'utilisation des classes Wrapper :
String str
= "1.23";
float primF = 3.456F;
Float objF;
primF = Float.MAX_VALUE;
primF = Float.MIN_VALUE;
// Plus grande valeur positive de type float
// Plus petite valeur positive de type float
objF
primF
objF
objF
str
str
primF
//
//
//
//
//
//
//
=
=
=
=
=
=
=
new Float(primF);
objF.floatValue();
new Float("2.34");
Float.valueOf(str);
objF.toString();
Float.toString(primF);
Float.parseFloat(str);
Conversion
Conversion
Conversion
Conversion
Conversion
Conversion
Conversion
float
Float
String
String
Float
float
String
->
->
->
->
->
->
->
Float
float
Float
Float
String
String
float
Ces exemples, donnés pour les types float et Float, s'appliquent par
analogie aux autres types primitifs (avec quelques légères différences pour
les types boolean et char).
EIA-FR / Jacques Bapst
PR1_11
17
Java / Membres statiques, initialiseurs, finaliseurs, wrappers
Autoboxing / Unboxing
§ Un mécanisme de conversions automatiques entre types primitifs et
classes Wrapper a été introduit dans le langage.
Complément
§ Lorsque c'est possible, le compilateur génère automatiquement le
code de conversion entre les variables de types primitifs et les
objets des classes Wrapper :
Type primitif
à Classe Wrapper
[ Autoboxing ]
Classe Wrapper
à Type primitif
[ Unboxing ]
...
int
i = 12, j, r;
Integer objA = new Integer(34), objB;
objB = i;
j
= objA;
r
= ++objA + i;
...
EIA-FR / Jacques Bapst
// Autoboxing
// Unboxing
PR1_11
18
Java / Sous-classes, héritage et polymorphisme
Arborescence de classes
Informatique / Programmation
§ L'héritage induit une relation arborescente entre les classes.
A
En notation UML, le symbole
signifie
"est une sous-classe de"
"hérite de"
B
Programmation orientée objet avec Java
12 : Sous-classes, héritage et polymorphisme
C
- La classe A
- La classe B
- La classe B
- Les classes
Jacques Bapst
[email protected]
D
est la classe parente (super-classe) de B
est la classe parente de C et D
est une sous-classe de A
C et D sont des sous-classes de B
B joue plusieurs rôles
EIA-FR / Jacques Bapst
Java / Sous-classes, héritage et polymorphisme
3
Java / Sous-classes, héritage et polymorphisme
Sous-classe et héritage
Exemple : classe Vehicule
§ L'héritage est une propriété essentielle de la programmation
orientée objet.
§ Pour illustrer le concept, prenons l'exemple d'une classe Vehicule
permettant de décrire (très sommairement) les propriétés et les
comportements d'un véhicule du monde réel.
§ Ce mécanisme permet d'ajouter des fonctionnalités à une classe
(une spécialisation) en créant une sous-classe qui hérite des
propriétés de la classe parente et à laquelle on peut ajouter des
propriétés nouvelles.
§ Avec une modélisation très simpliste, la classe pourrait être
représentée de la manière suivante :
§ La classe qui hérite est appelée sous-classe (ou classe dérivée)
de la classe parente (qui est également appelée super-classe).
Vehicule
marque
couleur
vitesse
etat
§ L'héritage permet à une sous-classe d'étendre les propriétés
de la classe parente tout en héritant des champs (attributs) et
des méthodes (comportement) de cette classe parente.
demarrer()
arreter()
accelerer()
freiner()
§ En Java, une classe ne peut hériter que d'une seule classe parente.
On parle dans ce cas d'héritage simple (par opposition à l'héritage
multiple qui permet à une classe d'hériter de plusieurs classes parentes).
EIA-FR / Jacques Bapst
PR1_12
PR1_12
2
EIA-FR / Jacques Bapst
PR1_12
4
Java / Sous-classes, héritage et polymorphisme
Java / Sous-classes, héritage et polymorphisme
Implémentation classe Vehicule
Sous-classes Voiture et Camion
public class Vehicule {
private
private
private
private
String
String
double
int
marque;
couleur;
vitesse;
etat;
§ La classe Voiture est une sous-classe de Vehicule.
Elle hérite de tous les attributs et méthodes de Vehicule (marque,
couleur, ..., freiner()) en y ajoutant deux nouveaux attributs
(modele et nbPortes).
// Vitesse actuelle
// 0:arrêt, 1:marche, ...
public Vehicule(String marque, String couleur) {
this.marque = marque;
this.couleur = couleur;
vitesse
= 0.0;
etat
= 0;
}
§ La classe Camion est également une sous-classe de Vehicule et
hérite de tous ses attributs et méthodes. La classe Camion étend la
classe parente (Vehicule) en y ajoutant deux nouveaux attributs
(chargeMax et poidsChargement) ainsi que deux nouvelles
méthodes (charger() et decharger()) .
public void demarrer() { etat = 1; }
public void arreter()
{ if (vitesse == 0) etat = 0; }
§ Dans les sous-classes Voiture et Camion, on peut utiliser les
attributs et les méthodes héritées (par exemple couleur ou
freiner()) comme si ces membres avaient été déclarés dans
chacune des sous-classes (sous réserve, naturellement, que les
droits d'accès le permettent).
public void accelerer() {
if (etat == 1) vitesse += 5.0;
}
}
public void freiner() {
if (vitesse >= 5.0) vitesse -= 5.0;
else
vitesse = 0.0;
}
EIA-FR / Jacques Bapst
PR1_12
5
EIA-FR / Jacques Bapst
Java / Sous-classes et héritage
Voiture
modele
nbPortes
Déclaration de sous-classe
§ La déclaration d'une sous-classe s'effectue en utilisant le mot-clé
extends suivi du nom de la classe parente :
Vehicule
marque
couleur
vitesse
etat
demarrer()
arreter()
accelerer()
freiner()
Dans le langage UML, un tel
diagramme est appelé
"Diagramme de classes".
public class Voiture extends Vehicule {
Il montre les relations entre
les classes d'une application
private String modele;
private int
nbPortes;
// Nouveau champ
// Nouveau champ
public Voiture(String
String
String
int
// Constructeur
marque,
modele,
couleur,
nbPortes) {
super(marque, couleur);
Camion
// Appelle le constructeur de la classe parente
this.modele
= modele;
this.nbPortes = nbPortes;
chargeMax
poidsChargement
}
charger()
decharger()
EIA-FR / Jacques Bapst
7
Java / Sous-classes, héritage et polymorphisme
Sous-classes de Vehicule
A partir de la classe
Vehicule on peut, en
utilisant l'héritage, créer
de nouvelles classes
(Voiture et Camion) qui
spécialisent la classe
Vehicule en y ajoutant
de nouvelles propriétés.
PR1_12
}
PR1_12
6
EIA-FR / Jacques Bapst
PR1_12
8
Java / Sous-classes, héritage et polymorphisme
Java / Sous-classes, héritage et polymorphisme
Relations entre classes [1]
Relations entre classes [2]
§ L'héritage entre une sous-classe et sa classe parente est
caractérisé par une relation de type
"Est un..."
"Est une sorte de..."
ou
§ Il existe une autre relation importante qui peut exister entre deux
classes. Il s'agit de la relation de composition (ou agrégation) qui
est caractérisée par une relation de type
("Is a...")
("Is kind of...")
"A un..."
"Possède un..."
"Est composé de..."
"Contient..."
ou
ou
ou
• Une voiture est un véhicule
• Un camion est un véhicule
Attention : l'inverse n'est pas forcément vrai !
• Une voiture possède un moteur
• Une voiture a un propriétaire
§ Une sous-classe crée une spécialisation de la classe parente.
A l'inverse, on parle de généralisation lorsqu'on passe des sousclasses à leur classe parente.
("Has a...")
"A un..." ð Composition
ð Agrégation
§ En Java, les relations de composition sont réalisées en créant
dans la classe "contenant" une référence vers un objet de la
classe "contenu".
§ Point à retenir lors de la conception d'une application :
public class Voiture extends Vehicule {
private Personne propriétaire;
private FuelMotor moteur;
"Est un..." ð Héritage
. . .
EIA-FR / Jacques Bapst
EIA-FR / Jacques Bapst
9
PR1_12
Java / Sous-classes, héritage et polymorphisme
PR1_12
11
Java / Sous-classes, héritage et polymorphisme
Généralisation / Spécialisation
Relations entre classes [3]
§ En notation UML, la relation "A un", "Possède un", … est
représentée de la manière suivante :
Voiture
Roman
Film
BD
Opera
Complément
Livre
Généralisation
Spécialisation
Oeuvre
Opera-Rock
Agrégation
Composition
1
4
Propriétaire
Roue
§ La distinction sémantique entre composition et agrégation ne se
traduit pas (en Java) par des différences d'implémentation.
public class Voiture extends Vehicule {
. . .
private Personne
private Roue[]
leProprietaire;
lesRoues;
. . .
}
EIA-FR / Jacques Bapst
PR1_12
10
EIA-FR / Jacques Bapst
PR1_12
12
Java / Sous-classes, héritage et polymorphisme
Java / Sous-classes, héritage et polymorphisme
Généralisation
Classe Object
Important !
§ La relation d'héritage ("Est un...") permet de traiter les objets
des sous-classes comme s'ils étaient des objets de leur classe
parente (par généralisation).
Camion
§ En Java, chaque classe que l'on crée possède une classe parente.
c1 = new Camion(...);
Vehicule v1 = c1;
Camion
c2 = v1;
Camion
c3 = (Camion)v1;
// Ok, un camion est un véhicule
// ERREUR, un véhicule n'est pas forcément un camion !
// Ok, v1 référence effectivement un camion
§ Une conversion explicite (transtypage, casting) d'un objet de la
classe parente vers un objet de la sous-classe (Downcasting) est
possible si l'instance à convertir référence effectivement ( au moment
de l'exécution) un objet de la sous-classe considérée (sinon, il y aura
une erreur ClassCastException à l'exécution).
PR1_12
§ La classe Object est donc l'ancêtre de toutes les classes Java
(c'est la racine unique de l'arbre des classes).
§ La classe Object est la seule classe Java qui ne possède pas de
classe parente.
§ Si nécessaire, le système effectue donc une conversion
élargissante (automatique) de la sous-classe vers la classe
parente (Upcasting).
EIA-FR / Jacques Bapst
§ Si l'on ne définit pas explicitement une classe parente (avec
extends), la super-classe par défaut est Object (qui est déclarée
dans le paquetage java.lang).
13
Java / Sous-classes, héritage et polymorphisme
§ Toutes les classes héritent donc des méthodes de la classe Object
(par exemple toString(), equals(), finalize(), etc).
§ La classe Object constitue la généralisation ultime :
Tous les objets sont des Object !
EIA-FR / Jacques Bapst
15
Java / Sous-classes, héritage et polymorphisme
Opérateur instanceof
Chaînage des constructeurs
§ Un constructeur d'une sous-classe peut faire appel à un
constructeur de la classe parente en utilisant le mot réservé
super selon la syntaxe suivante :
super(Expr1, Expr2, ...);
§ L'opérateur instanceof permet de tester (à l'exécution)
l'appartenance d'un objet à une classe (ou une interface) donnée.
§ Dans l'exemple précédent, on aurait pu écrire :
if (v1 instanceof Camion) {
c3 = (Camion)v1;
}
else {
... // v1 ne référence pas un Camion
}
§ Si un constructeur d'une sous-classe invoque explicitement un
constructeur de la classe parente, l'instruction super( ...) doit être
la première instruction du constructeur.
§ Si l'on ne fait pas explicitement appel à un constructeur de la
classe parente, une invocation du constructeur par défaut de
la super-classe (constructeur sans paramètre) sera
automatiquement ajoutée (comme première instruction). Si un tel
constructeur n'existe pas dans la classe parente, une erreur sera
générée à la compilation.
Un tel test permet d'éviter une erreur fatale (à l'exécution) si la
variable v1 ne référence pas un objet de type Camion.
Remarque 1 : (v1 instanceof Vehicule) est également vrai !
Remarque 2 : L'upcasting et le downcasting n'engendrent aucune opération
ni changement en mémoire (c'est une autre "vue" de l'objet)
EIA-FR / Jacques Bapst
PR1_12
PR1_12
14
§ Le langage garantit ainsi que tous les éléments des classes
parentes aient été élaborés avant la création d'un objet de la
classe considérée.
EIA-FR / Jacques Bapst
PR1_12
16
Java / Sous-classes, héritage et polymorphisme
Java / Sous-classes, héritage et polymorphisme
Masquage des champs
Redéfinition des méthodes [2]
§ Les classes Polygone et Rectangle définissent toutes deux une
méthode area() avec une signature identique.
Complément
§ Si une sous-classe définit un champ avec le même nom qu'un
champ de sa classe parente (une pratique à éviter), alors le champ
de la super-classe est masqué dans le corps de la sous-classe.
§ La méthode invoquée par un appel obj.area() dépendra du type
de l'objet référencé par la variable obj lors de l'exécution
de cette instruction.
§ Dans ce cas, on peut, dans le corps de la sous-classe accéder
au champ de la classe parente en utilisant le mot-clé super suivi
d'un point et du nom du champ.
§ C'est toujours la méthode associée au type effectif de l'objet
référencé qui est exécutée, même si l'objet est enregistré dans
une variable déclarée avec le type d'une classe parente :
§ Si les classes A et B définissent toutes deux un champ x et que B
est une sous-classe de A alors, dans les méthodes de B, on peut
utiliser : x
Champ x de la classe B
this.x
super.x
((A)this).x
Champ x de la classe B
Champ x de la classe A
Champ x de la classe A (par transtypage)
Rectangle r = new Rectangle(2.6, 5.3);
Polygon
La notation super.super.x n'est pas autorisée, seul le casting (((A)c).x) permet
d'accéder à un champ masqué d'une classe ancêtre.
p = r;
double s = p.area();
§ Les champs statiques peuvent également être masqués mais ils
restent accessibles en les préfixant avec le nom de la classe.
EIA-FR / Jacques Bapst
PR1_12
17
Java / Sous-classes, héritage et polymorphisme
Rectangle
EIA-FR / Jacques Bapst
EIA-FR / Jacques Bapst
PR1_12
19
Redéfinition des méthodes [3]
§ Lorsqu'une classe définit une méthode d'instance en utilisant
la même signature (même nom, type de retour [év. une sous-classe],
paramètres, etc.) qu'une méthode de sa classe parente, cette
méthode redéfinit (overrides) la méthode de sa super-classe.
Polygon
// Invoque r.area() et non pas area() de la
// classe Polygon car la variable p référence
// un objet de type Rectangle
Java / Sous-classes, héritage et polymorphisme
Redéfinition des méthodes [1]
§ Par exemple :
// Conversion élargissante (Upcasting)
§ Dans la sous-classe Rectangle, il est possible d'invoquer la
méthode area() de la classe parente Polygon en utilisant
la notation suivante :
super.area()
Remarque : La notation super.super.f() n'est pas autorisée et il est
impossible d'accéder à une méthode masquée d'une classe
ancêtre (autre que la classe parente).
public class Polygon {
. . .
public double area() {
. . . // Calcul de la surface d'un polygone quelconque
}
. . .
}
§ A l'extérieur de la classe de déclaration, il n'est, par contre, pas
possible pour un objet de type Rectangle, d'invoquer la méthode
area de la classe Polygon.
public class Rectangle extends Polygon {
. . .
public double area() {
. . . // Calcul de la surface du rectangle (longueur*largeur)
}
. . .
}
PR1_12
§ Attention à bien distinguer (et ne pas confondre) les notions de
surcharge (overloading) et de redéfinition (overriding) de
méthodes.
18
EIA-FR / Jacques Bapst
PR1_12
20
Java / Sous-classes, héritage et polymorphisme
Java / Sous-classes, héritage et polymorphisme
Redéfinition des méthodes [4]
Redéfinition des méthodes [6]
§ L’annotation @Override peut être utilisée pour indiquer
explicitement l’intention de redéfinir une méthode.
§ Si une méthode est redéfinie dans une sous-classe, le type de
retour doit être identique à celui de la méthode correspondante
de la classe parente.
• Si on se trompe en écrivant le nom de la méthode lors de la
redéfinition, le compilateur peut alors informer le programmeur
de son erreur.
Complément
Complément
§ Bien qu’étant facultative, elle apporte deux avantages :
• La redéfinition étant explicite, le code est plus clair.
@Override
public double area() { … }
§ En redéfinissant une méthode, il est possible d'étendre sa zone de
visibilité (private à package à protected à public) mais non de la
restreindre.
§ Une méthode redéfinie ne peut pas générer plus d'exceptions
contrôlées que celles qui sont déclarées dans la méthode de la
classe parente (mais elle peut en déclarer moins).
§ Éviter de :
• surcharger une méthode qui est redéfinie
• redéfinir une partie des méthodes surchargées
car cela provoque des risques de confusion et crée des pièges lors
des modifications ultérieures des classes.
EIA-FR / Jacques Bapst
PR1_12
21
Java / Sous-classes, héritage et polymorphisme
EIA-FR / Jacques Bapst
23
Java / Sous-classes, héritage et polymorphisme
Redéfinition des méthodes [5]
Complément
PR1_12
Modificateur final
§ Les méthodes statiques (méthodes de classe) peuvent être
masquées, dans des sous-classes, par des méthodes statiques
possédant le même nom (*** une pratique à éviter ***).
§ Dans la déclaration d'une classe, le modificateur final indique
que la classe ne peut pas être sous-classée (on ne peut pas créer
de classes dérivées).
§ Ces méthodes masquées restent cependant accessibles en
les préfixant avec le nom de la classe dans laquelle elles sont
définies (comme il est recommandé de le faire avec toutes les méthodes
statiques).
§ Dans la déclaration d'un champ, le modificateur final indique
que la valeur du champ ne peut pas être modifiée après l'affectation
initiale (dans la déclaration ou dans le constructeur). Permet de
définir des valeurs constantes.
§ Dans la déclaration d'une méthode, le modificateur final indique
que la méthode ne peut pas être redéfinie dans une sous-classe.
§ On ne peut donc pas spécialiser une méthode statique dans une
sous-classe (comme les méthodes statiques ne sont jamais
associées à un objet, le polymorphisme de s'applique pas).
§ Dans la déclaration des paramètres d'une méthode, le
modificateur final indique que la valeur de ces paramètres ne peut
pas être modifiée (il s'agit de paramètres d'entrée de la méthode).
§ En outre, une méthode statique ne peut pas masquer une
méthode d'instance d'une super-classe (erreur à la compilation).
Remarque : L'utilisation du modificateur final permet en outre au compilateur
d'effectuer certaines optimisations : mise en ligne de méthodes
(inlining), suppression de la recherche dynamique (late binding), etc.
EIA-FR / Jacques Bapst
PR1_12
22
EIA-FR / Jacques Bapst
PR1_12
24
Java / Sous-classes, héritage et polymorphisme
Java / Sous-classes, héritage et polymorphisme
Modificateur protected
Polymorphisme [1]
§ Le modificateur protected appliqué aux membres (champs
ou méthodes) d'une classe indique que ces champs ne sont
accessibles que dans la classe de définition, dans les classes
du même paquetage et dans les sous-classes de cette classe
(indépendamment du paquetage).
§ Si l'on considère le diagramme de classes suivant :
Animal
age
poids
mange()
dort()
§ Il s'agit d'un accès plus restrictif que public mais - contrairement
à ce que son nom pourrait laisser croire - moins restrictif que
l'accès par défaut (package).
§ Le modificateur protected devrait être utilisé avec les champs et
les méthodes qui ne sont pas requis par les utilisateurs de la classe
mais qui pourraient s'avérer utiles à la création de sous-classes
dans d'autres paquetages.
EIA-FR / Jacques Bapst
PR1_12
25
Java / Sous-classes, héritage et polymorphisme
Chien
nom
mange()
joue()
mange()
nage()
EIA-FR / Jacques Bapst
PR1_12
27
Java / Sous-classes, héritage et polymorphisme
Modificateur private
Polymorphisme [2]
§ Le modificateur private, appliqué aux membres (champs ou
méthodes) d'une classe, indique que ces champs ne sont
accessibles que dans la classe de définition.
§ On peut déduire du diagramme de classes les considérations
suivantes :
• Chien et Poisson sont des sous-classes d'Animal
• Animal est la classe parente de Chien et de Poisson
§ Même s'il ne sont pas accessibles dans les sous-classes, les
champs privés sont malgré tout hérités dans les sous-classes
(une zone mémoire leur est allouée).
• Chien hérite des membres d'Animal (age, poids, dort())
• Chien ajoute le champ nom
• Chien ajoute la méthode joue()
• Chien redéfinit la méthode mange()
§ Il s'agit de l'accès le plus restrictif.
§ Le modificateur private devrait être utilisé avec les champs et
les méthodes qui ne sont utilisés qu'au sein de la classe de
définition et qui devraient être cachés partout ailleurs.
Conseil : D'une manière générale il vaut mieux commencer par un accès
restrictif aux membres d'une classe ( ð private).
Si nécessaire, il est toujours possible de relâcher les restrictions dans
des versions ultérieures de la classe.
Un relâchement des restrictions préserve la compatibilité ascendante
(ce qui n'est pas le cas si l'on restreint les droits d'accès).
EIA-FR / Jacques Bapst
Poisson
PR1_12
26
• Poisson hérite des membres d'Animal (age, poids, dort())
• Poisson ajoute la méthode nage()
• Poisson redéfinit la méthode mange()
EIA-FR / Jacques Bapst
PR1_12
28
Java / Sous-classes, héritage et polymorphisme
Java / Sous-classes, héritage et polymorphisme
Polymorphisme [3]
Polymorphisme [5]
§ Si l'on implémente les classes Animal, Chien et Poisson
et que l'on écrit le code suivant :
§ En Java, dans la plupart des situations où il y a des relations
d'héritage, la détermination de la méthode à invoquer n'est pas
effectuée lors de la compilation.
Chien milou = new Chien(...);
milou.mange();
§ C'est seulement à l'exécution que la machine virtuelle déterminera
la méthode à invoquer selon le type effectif de l'objet référencé à ce
moment là.
§ La méthode mange() qui sera invoquée est celle qui est définie
dans la sous-classe Chien (car milou est du type Chien et la
méthode mange() est redéfinie pour cette sous-classe).
§ Ce mécanisme s'appelle "Recherche dynamique de méthode"
(Late Binding ou Dynamic Binding).
§ Si la sous-classe Chien ne redéfinissait pas la méthode mange(),
ce serait alors la méthode mange() d'Animal qui serait invoquée
(la classe Chien en hériterait).
EIA-FR / Jacques Bapst
PR1_12
§ Ce mécanisme de recherche dynamique (durant l'exécution
de l'application) sert de base à la mise en oeuvre de la propriété
appelée polymorphisme.
29
Java / Sous-classes, héritage et polymorphisme
EIA-FR / Jacques Bapst
PR1_12
31
Java / Sous-classes, héritage et polymorphisme
Polymorphisme [4]
Polymorphisme [6]
§ Comme un Chien est un Animal (relation d'héritage) on peut écrire
le code suivant :
Animal toutou = new Chien(...);
toutou.mange();
§ On pourrait définir le polymorphisme comme la propriété
permettant à un programme de réagir de manière différenciée
à l'envoi d'un même message (invocation de méthode) en
fonction des objets qui reçoivent ce message.
§ Quelle méthode mange() sera invoquée dans ce cas ?
§ Il s'agit donc d'une aptitude d'adaptation dynamique du
comportement selon les objets en présence.
§ C'est toujours la méthode mange() définie dans la sous-classe
Chien qui sera invoquée.
§ Avec l'encapsulation et l'héritage, le polymorphisme est une des
propriétés essentielles de la programmation orientée objet.
§ Même si toutou est une référence de type Animal, c'est le type de
l'objet référencé qui détermine la méthode qui sera appelée
(comportement décrit sous "Redéfinition des méthodes").
EIA-FR / Jacques Bapst
PR1_12
30
Remarque : La surcharge de méthodes peut également être considérée
comme une forme de polymorphisme. Le choix de la méthode
à invoquer est cependant déterminé à la compilation
EIA-FR / Jacques Bapst
PR1_12
32
Java / Sous-classes, héritage et polymorphisme
Java / Sous-classes, héritage et polymorphisme
Exemple de polymorphisme [1]
Exemple de polymorphisme [3]
§ On peut ensuite appeler la méthode nourrir() en lui passant en
paramètre la ménagerie précédemment créée :
§ L'exemple qui suit est destiné à illustrer le principe du
polymorphisme. Il se base sur les classes précédemment
définies (Animal, Chien et Poisson).
nourrir(menagerie);
§ Si l'on souhaite enregistrer et manipuler une collection d'animaux
(une ménagerie) on peut créer et alimenter le tableau suivant :
§ Sur la base du contenu de menagerie, la méthode nourrir()
appellera successivement : mange() de la classe Poisson
mange()
mange()
mange()
mange()
mange()
// Déclaration et création du tableau
Animal[] menagerie = new Animal[6];
// Alimentation du tableau
menagerie[0] = new Poisson(...);
menagerie[1] = new Chien(...);
menagerie[2] = new Chien(...);
menagerie[3] = new Animal(...);
menagerie[4] = new Poisson(...);
menagerie[5] = new Chien(...);
EIA-FR / Jacques Bapst
la
la
la
la
la
classe
classe
classe
classe
classe
Chien
Chien
Animal
Poisson
Chien
§ La méthode nourrir() n'a pas besoin de déterminer elle-même
quelle méthode doit être appelée pour chaque animal.
§ Le polymorphisme fera en sorte que le message mange() soit
interprété (à l'exécution) de manière appropriée selon les objets
qui le reçoivent (ainsi chaque animal mangera selon ses goûts !).
PR1_12
33
Java / Sous-classes, héritage et polymorphisme
EIA-FR / Jacques Bapst
PR1_12
35
Java / Sous-classes, héritage et polymorphisme
Polymorphisme – Synthèse du mécanisme
Exemple de polymorphisme [2]
§ Le polymorphisme nous permet d'écrire une méthode nourrir dont
la fonction est de donner à manger à chaque animal contenu dans
le tableau passé en paramètre en appelant successivement
la méthode mange() pour chacun d'eux.
//--------------------------------------------------// Appelle la méthode mange() pour chaque animal contenu
// dans le tableau passé en paramètre
//--------------------------------------------------public static void nourrir(Animal[] tabAnimaux) {
§ En Java, les variables sont typées. Avec la notion d'héritage,
plusieurs «types» peuvent être compatibles avec une déclaration
de variable.
short s; // Ne peut rien contenir d'autre qu'un short
Object o;
// Peut contenir une référence vers un Object,
// ou un objet d’une sous-classe
§ Le compilateur s’assure que les instructions sont compatibles avec
la déclaration : Object o;
o = "ah";
int i=o.length(); // Refusé, car length() Ï Object
int i=((String)o).length(); // Ok si o référence un String
§ A l’exécution, Java « suit toujours la flèche » pour atteindre les
méthodes :
Animal a;
if (tabAnimaux == null) return;
for (int i=0; i<tabAnimaux.length; i++) {
if (tabAnimaux[i] != null) {
tabAnimaux[i].mange();
}
}
a = new Chien();
a.mange();
// Ce sera bien la méthode redéfinie par la
// classe Chien qui sera exécutée
public class Animal {
void mange() {...}
}
}
EIA-FR / Jacques Bapst
de
de
de
de
de
PR1_12
34
EIA-FR / Jacques Bapst
public class Chien extends Animal {
void mange() {...} // Redéfinition !
}
PR1_12
36
Java / Classes abstraites et interfaces
Classes abstraites : métaphore
Informatique / Programmation
§ Comme les autres classes (et les interfaces), une classe abstraite
définit un nouveau type qui peut être associé à un identificateur
(déclaration de variables, champs, tableaux, paramètres formels, …).
§ Comme nous l'avons vu dans un des chapitres précédents, les
classes peuvent être considérées comme étant des moules (des
modèles, des plans, ...) permettant de fabriquer des objets.
Programmation orientée objet avec Java
§ Si l'on poursuit avec cette métaphore, les classes abstraites
peuvent être considérées comme étant des moules incomplets
(des modèles partiels, des plans non terminés, ...) qui ne
peuvent pas être utilisés tels quels pour créer des objets mais qui
peuvent être utilisés pour fabriquer d'autres plans plus précis
(représentés par des sous-classes) qui seront complétés et qui
permettront, eux, de créer des objets (des instances des sousclasses).
13 : Classes abstraites et interfaces
Jacques Bapst
[email protected]
EIA-FR / Jacques Bapst
Java / Classes abstraites et interfaces
PR1_13
3
Java / Classes abstraites et interfaces
Classes et méthodes abstraites
Classes abstraites
§ Une classe abstraite est une classe qui contient une ou plusieurs
méthodes abstraites. Elle peut malgré tout contenir d'autres
méthodes habituelles (appelée parfois méthodes concrètes).
Classe
abstraite
extends
Classe
concrète
new
Instances
(Objets)
§ Une méthode abstraite est une méthode qui ne contient pas
de corps. Elle possède simplement une signature de définition
suivie du caractère point-virgule (pas de bloc d'instructions).
Objet 1
§ Une méthode abstraite doit obligatoirement être déclarée avec
le modificateur abstract.
§ Exemple :
Objet 2
public abstract double area();
§ Une classe possédant une ou plusieurs méthodes abstraites
devient obligatoirement une classe abstraite. Cette classe doit
également être déclarée avec le modificateur abstract.
EIA-FR / Jacques Bapst
PR1_13
Objet 3
2
EIA-FR / Jacques Bapst
PR1_13
4
Java / Classes abstraites et interfaces
Java / Classes abstraites et interfaces
Utilité des classes abstraites
Classes abstraites : règles [1]
§ En pratique, les classes abstraites permettent de définir des
fonctionnalités (des comportements) que les sous-classes
devront impérativement implémenter même si la classe
abstraite n'est pas en mesure de fournir elle-même une
implémentation pour ces méthodes.
§ Les règles suivantes s'appliquent aux classes abstraites :
• Une classe abstraite ne peut pas être instanciée : on ne peut pas
créer d'objet en utilisant l'opérateur new.
• Une sous-classe d'une classe abstraite ne peut être instanciée que
si elle redéfinit chaque méthode abstraite de sa classe parente et
qu'elle fournit une implémentation (un corps) pour chacune des
méthodes abstraites.
Une telle sous-classe est souvent appelée sous-classe concrète afin
de mettre en évidence le fait qu'elle n'est pas abstraite.
§ Les utilisateurs des sous-classes d'une classe abstraite sont donc
assurés de trouver toutes les méthodes définies dans la classe
abstraite dans chacune des sous-classes concrètes.
§ Les classes abstraites constituent donc une sorte de contrat
(spécification contraignante) qui garantit que certaines méthodes
seront disponibles dans les sous-classes et qui oblige les
programmeurs à les implémenter dans toutes les sous-classes
concrètes.
• Si une sous-classe d'une classe abstraite n'implémente pas toutes les
méthodes abstraites dont elle hérite, cette sous-classe est elle-même
abstraite (et ne peut donc pas être instanciée).
• Les méthodes déclarées avec l'un des modificateurs suivants :
static, private ou final ne peuvent pas être abstraites étant donné
qu'elles ne peuvent pas être redéfinies dans une sous-classe.
EIA-FR / Jacques Bapst
PR1_13
5
Java / Classes abstraites et interfaces
EIA-FR / Jacques Bapst
PR1_13
Java / Classes abstraites et interfaces
Classes abstraites : règles [2]
Exemple de classe abstraite [1]
§ Autres règles s'appliquant aux classes abstraites :
§ Si l'on souhaite, par exemple, créer une hiérarchie de classes qui
décrive des formes géométriques à deux dimensions, on pourrait
envisager l'arborescence représentée par le diagramme de classes
suivant :
• Une classe déclarée final ne peut pas contenir de méthodes
abstraites car elle ne peut pas être sous-classée.
• Une classe peut être déclarée abstract même si elle ne possède
pas réellement de méthode abstraite.
Shape
Cela signifie que son implémentation est incomplète en certains
points (p. ex. le corps de certaines méthodes doit être complété
en fonction du contexte) et qu'elle est destinée à jouer le rôle de
classe parente pour une ou plusieurs sous-classes qui achèveront
l'implémentation.
Circle
Même si elle ne possède pas de méthodes abstraites, une telle
classe ne peut pas être instanciée (erreur à la compilation).
EIA-FR / Jacques Bapst
7
PR1_13
Rectangle
Square
6
EIA-FR / Jacques Bapst
Triangle
...
...
PR1_13
8
Java / Classes abstraites et interfaces
Java / Classes abstraites et interfaces
Exemple de classe abstraite [2]
Exemple de classe abstraite [4]
§ Sachant que toutes les formes possèdent les propriétés
périmètre et surface, il est judicieux de placer les méthodes
définissant ces propriétés (perimeter() et area()) dans la
classe qui est à la racine de l'arborescence (Shape).
//----------------------------------------------------------// Rectangle
//----------------------------------------------------------public class Rectangle extends Shape {
protected double length, width;
§ La classe Shape ne peut cependant pas implémenter ces deux
méthodes car on ne peut pas calculer le périmètre et la surface
sans connaître le détail de la forme.
public Rectangle(double length, double width) {
this.length = length;
this.width = width;
}
§ On pourrait naturellement implémenter ces méthodes dans
chacune des sous-classes de Shape mais il n'y a aucune garantie
que toutes les sous-classes les possèdent (ce serait laissé au
bon vouloir des programmeurs des sous-classes).
public double getLength()
{ return length; }
public double getWidth()
{ return width; }
public double perimetre() {
return 2*(length + width);
}
§ Il est possible de résoudre ce problème en déclarant dans la
classe Shape deux méthodes abstraites perimeter() et area()
ce qui rend la classe Shape elle-même abstraite et impose aux
créateurs de sous-classes de les implémenter.
EIA-FR / Jacques Bapst
PR1_13
}
9
Java / Classes abstraites et interfaces
EIA-FR / Jacques Bapst
PR1_13
11
Java / Classes abstraites et interfaces
Exemple de classe abstraite [3]
Exemple de classe abstraite [5]
§ Les autres sous-classes (Square, Triangle, ...) pourraient être
implémentées selon le même modèle.
//----------------------------------------------------------// Shape
//----------------------------------------------------------public abstract class Shape {
// Classe abstraite
public abstract double perimeter(); // Méthode abstraite
public abstract double area();
// Méthode abstraite
}
§ Même si la classe Shape est abstraite, il est tout de même possible
de déclarer des variables de ce type qui pourront recevoir des
objets créés à partir des sous-classes concrètes :
//----------------------------------------------------------// Circle
//----------------------------------------------------------public class Circle extends Shape {
public static final double PI = 3.14159265358979;
private double radius;
Shape[] drawing = new Shape[3];
drawing[0] = new Rectangle(2.5, 6.8);
drawing[1] = new Circle(4.66);
drawing[2] = new Square(0.125);
// Conversion élargissante
// Conversion élargissante
// Conversion élargissante
§ Le polymorphisme permet ensuite d'invoquer une méthode
commune sur chacun des objets :
public Circle(double radius) {
this.radius = radius;
}
double totalArea = 0.0;
public double getRadius() { return radius; }
for (int i=0; i<drawing.length; i++) {
totalArea += drawing[i].area();
}
public double perimeter() { return 2*PI*radius; }
public double area()
public double surface() {
return length * width;
}
{ return PI*radius*radius; }
// Calcule la somme
// des surfaces
}
EIA-FR / Jacques Bapst
PR1_13
10
EIA-FR / Jacques Bapst
PR1_13
12
Java / Classes abstraites et interfaces
Java / Classes abstraites et interfaces
Interface [1]
Interface [3]
§ Comme une classe et une classe abstraite, une interface permet
de définir un nouveau type (référence).
§ Le corps d'une interface peut contenir :
• Des constantes qui sont implicitement publiques
§ Le comportement des objets de ce type (les opérations que l'on
peut effectuer) sera déterminé par le contenu (la définition) de
cette interface.
ü Les modificateurs static et final ne sont pas nécessaires (implicites).
• Des méthodes abstraites qui sont obligatoirement publiques
ü Le modificateur abstract n'est pas nécessaire (implicite).
§ Une interface constitue essentiellement une spécification qui
laisse de côté les détails d'implémentation.
ü Le modificateur public n'est pas nécessaire (implicite).
§ L'interface définit ainsi une sorte de contrat que les classes qui
l'implémenteront s'engagent à respecter.
• Des méthodes avec une implémentation par défaut
§ Les interfaces jouent un rôle important dans la phase de
conception (API) d'applications, de librairies ou de systèmes
basés sur des ensembles d'objets qui communiquent.
• Des méthodes statiques.
ü Le modificateur default doit être utilisé.
§ Par contre
• Une interface ne peut pas définir de champs d'instance.
§ Par certains aspects, la notion d'interface est assez proche de
la notion de classe abstraite mais elle comporte cependant un
certain nombre de spécificités qui l'en distinguent et qui en
étendent le potentiel.
EIA-FR / Jacques Bapst
PR1_13
• Une interface ne définit pas de constructeur (on ne peut pas
l'instancier et elle n'intervient pas dans le chaînage des constructeurs ).
13
Java / Classes abstraites et interfaces
EIA-FR / Jacques Bapst
Utilisation des interfaces [1]
§ Du point de vue syntaxique, la définition d'une interface est proche
de celle d'une classe abstraite.
§ En Java, une classe ne peut hériter que d'une et d'une seule classe
parente (héritage simple).
§ Il suffit de remplacer les mots-clés abstract class par le motclé interface :
§ Une classe peut, par contre, implémenter une ou plusieurs
interfaces en utilisant la syntaxe suivante :
public interface Printable {
public void print();
}
implements interface1, interface2, ...
§ L'implémentation d'une ou de plusieurs interfaces (implements) peut
être combinée avec l'héritage simple (extends).
La clause implements doit suivre la clause extends.
§ Une fois l'interface déclarée, il est possible de déclarer des
variables de ce (nouveau) type :
EIA-FR / Jacques Bapst
15
Java / Classes abstraites et interfaces
Interface [2]
Printable
Printable[]
PR1_13
§ Exemples :
document;
printSpool;
PR1_13
14
public class Report
implements Printable {...}
public class Book
implements Printable, Zoomable {...}
public class Circle
extends Shape implements Printable {...}
public class Square
extends Rectangle
implements Printable, Zoomable {...}
EIA-FR / Jacques Bapst
PR1_13
16
Java / Classes abstraites et interfaces
Java / Classes abstraites et interfaces
Utilisation des interfaces [2]
Exemple d'interface [2]
§ Tous les objets dont la classe implémente l'interface Comparable
pourront ensuite être triés.
§ Lorsqu'une classe déclare une interface dans sa clause
implements, elle indique ainsi qu'elle s'engage à fournir une
implémentation (c'est-à-dire un corps) pour chacune des
méthodes abstraites de cette interface.
§ Si une classe implémente une interface mais ne fournit pas
d'implémentation pour toutes les méthodes abstraites de l'interface,
elle hérite des méthodes (abstraites) non implémentées de
l'interface et doit elle-même être déclarée abstract.
§ Si une classe implémente plus d'une interface, elle doit implémenter
toutes les méthodes abstraites de chacune des interfaces
mentionnées dans la clause implements (ou alors être déclarée
abstract).
. . .
Person[] population;
. . .
Tools.sort(population);
. . .
§ Les méthodes de l'interface qui sont déclarées avec une
implémentation par défaut peuvent être redéfinies (ou non) dans
les classes qui implémentent l'interface.
EIA-FR / Jacques Bapst
PR1_13
public class Person implements Comparable {
. . .
private int age;
. . .
public int compareTo(Object p) {
if (p instanceof Person) {
if (this.age < ((Person)p).age) return -1;
if (this.age > ((Person)p).age) return 1;
return 0;
}
else . . .
}
. . .
}
17
Java / Classes abstraites et interfaces
EIA-FR / Jacques Bapst
Exemple d'interface [3]
§ Si l'on souhaite caractériser la fonctionnalité de comparaison qui
est commune à tous les objets qui ont une relation d'ordre (plus
petit, égal, plus grand), on peut définir l'interface Comparable de la
manière suivante :
§ Supposons que nous voulions que les classes dérivées de
la classe Shape disposent toutes d'une méthode print()
permettant d'imprimer les formes géométriques.
§ Il serait naturellement possible d'ajouter une méthode abstraite
print() à la classe Shape et ainsi chacune des sous-classes
concrètes devrait implémenter cette méthode.
L'utilisateur de ces sous-classes serait ainsi sûr de disposer
d'une méthode print() lui permettant d'imprimer la forme.
public interface Comparable {
public int compareTo(Object v);
}
§ Cette interface définit un type de données qui peut ensuite être
utilisé dans des traitements qui nécessitent une relation d'ordre,
dans une méthode de tri par exemple :
§ Avec cette solution, le problème serait résolu pour toutes les
sous-classes de Shape, mais si d'autres classes (qui n'héritent
pas de Shape) souhaitaient également disposer des fonctions
d'impression, elles devraient à nouveau déclarer des méthodes
abstraites d'impression dans leur arborescence.
public class Tools {
. . .
public static void sort(Comparable[] t) {
. . .
§ L'utilisation d'une interface permet de résoudre ce problème de
manière plus élégante en découplant la fonctionnalité
d'impression de la hiérarchie des classes.
. . .
. . .
}
. . .
}
EIA-FR / Jacques Bapst
19
Java / Classes abstraites et interfaces
Exemple d'interface [1]
if (t[i].compareTo(t[j]) > 0)
PR1_13
PR1_13
18
EIA-FR / Jacques Bapst
PR1_13
20
Java / Classes abstraites et interfaces
Java / Classes abstraites et interfaces
Exemple d'interface [4]
Exemple d'interface [6]
§ Au lieu d'ajouter une méthode abstraite print() dans la classe
Shape nous créons une interface nommée Printable qui définit la
méthode abstraite print() :
§ L'implémentation des sous-classes de Shape s'effectue donc de la
même manière que si la méthode print() avait été déclarée
comme méthode abstraite dans Shape.
§ L'avantage de l'interface Printable réside dans le fait qu'elle peut
être utilisée avec d'autres classes qui n'ont rien à voir avec la
classe Shape :
public interface Printable {
public void print();
}
public class Book extends Document implements Printable {
...
}
§ Et nous déclarons que la classe Shape implémente l'interface
Printable (le corps de la classe Shape reste inchangé) :
§ Un autre avantage est que l'interface Printable peut être
utilisée en combinaison avec d'autres interfaces, ce qui n'est pas
possible avec les classes ( car une sous-classe ne peut pas avoir
plusieurs super-classes).
public abstract class Shape implements Printable {
public abstract double perimeter(); // Méthode abstraite
public abstract double area();
// Méthode abstraite
}
public class Book extends Document
implements Printable, Zoomable {
...
}
EIA-FR / Jacques Bapst
PR1_13
21
Java / Classes abstraites et interfaces
EIA-FR / Jacques Bapst
Interface fonctionnelle
§ Une interface fonctionnelle est une interface comprenant
exactement une méthode abstraite.
§ Chaque sous-classe concrète de Shape devra obligatoirement
implémenter le corps de la méthode print() (en plus des méthodes
abstraites perimeter() et area()) :
§ Une interface fonctionnelle peut malgré tout comporter des
constantes, des méthodes avec une implémentation par défaut, des
méthodes redéclarant certaines méthodes de la classe Object ainsi
que des méthodes statiques.
//---------------------------------------------------------// Circle
//---------------------------------------------------------public class Circle extends Shape {
public static final double PI = 3.14159265358979;
private double radius;
§ La notion d'interface fonctionnelle joue un rôle important en lien
avec l'utilisation des expressions Lambda.
§ L'annotation @FunctionalInterface peut précéder la déclaration
des interfaces fonctionnelles. Ainsi, le compilateur vérifiera que les
règles énoncées soient respectées.
public Circle(double radius) {
this.radius = radius;
}
public double getRadius() { return radius; }
@FunctionalInterface
public interface SimpleFuncInterface {
public void doWork();
}
public double perimeter() { return 2*PI*radius; }
{ return PI*radius*radius; }
public void print() { ... }
}
EIA-FR / Jacques Bapst
23
Java / Classes abstraites et interfaces
Exemple d'interface [5]
public double area()
PR1_13
PR1_13
22
EIA-FR / Jacques Bapst
PR1_13
24
Java / Classes abstraites et interfaces
Java / Classes abstraites et interfaces
Gestion des exceptions
Classe abstraite ou interface ?
§ Lors de la conception d'une application ou d'une librairie, le choix
conceptuel entre une classe abstraite et une interface n'est pas
toujours facile.
§ Les méthodes concrètes ne peuvent pas annoncer plus
d'exceptions contrôlées dans leurs clauses throws, que celles
qui sont annoncées dans la déclaration des méthodes abstraites
qu'elles implémentent (déclaration dans classe abstraite ou interface).
§ Parmi les points à prendre en considération, on peut rappeler
que :
public interface Writable {
public void write(Object o) throws IOException, MemOverflow;
}
• Une classe peut implémenter plusieurs interfaces mais ne peut
hériter que d'une seule classe abstraite.
• Une interface peut être implémentée par une classe sans qu'il y ait
de rapports étroits entre les deux. Une sous-classe est liée par une
relation plus forte ("Est un ..." ).
• Les classes abstraites et les interfaces permettent de définir des
implémentation par défaut pour les méthodes.
public class Buffer implements Writable {
public void write(Object o) throws MemOverflow,
ArithmeticException
…
}
}
• Les interfaces fonctionnelles (une seule méthode abstraite) peuvent
être implémentées par des expressions Lambdas ou des références
de méthodes permettant ainsi d'alléger le code.
La méthode concrète write() n'a pas l'obligation d'annoncer toutes les exceptions
définies dans l'interface Writable (on ne peut pas imposer une liste d'exceptions).
{
Elle ne peut pas annoncer d'exceptions contrôlées supplémentaires mais peut ajouter
des exceptions non-contrôlées (comme ArithmeticException par exemple).
EIA-FR / Jacques Bapst
PR1_13
25
Java / Classes abstraites et interfaces
EIA-FR / Jacques Bapst
PR1_13
Java / Classes abstraites et interfaces
Extension des interfaces
Conflits de noms [1]
§ Des conflits de noms (collision) peuvent se produire lorsqu'une
classe implémente plusieurs interfaces comportant des noms de
méthodes ou de constantes identiques.
§ Les interfaces peuvent avoir des sous-interfaces (tout comme les
classes peuvent avoir des sous-classes). Comme pour les classes, le
mot-clé extends est utilisé pour créer une sous-interface.
§ Il faut distinguer plusieurs situations :
public interface Zoomable extends Observable {...}
• Plusieurs méthodes portent des signatures identiques :
§ Une sous-interface hérite de toutes les méthodes et de toutes les
constantes de son interface parente et peut définir de nouvelles
méthodes ainsi que de nouvelles constantes.
• Mêmes noms de méthodes mais profils de paramètres différents :
§ Contrairement aux classes, une interface peut posséder plusieurs
interfaces parentes (héritage multiple).
• Mêmes noms de méthodes, profils de paramètres identiques, mais
types des valeurs de retour différents :
ü Pas de problème, la classe doit implémenter cette méthode
ü Implémentation de deux ou plusieurs méthodes surchargées
public interface Transformable
extends Scalable, Translatable, Rotatable {...}
ü Pas possible d'implémenter les deux interfaces (cela provoquera une
erreur à la compilation : Interface-Collision)
• Seulement les listes d'exceptions sont différentes :
§ Une classe qui implémente une sous-interface doit implémenter
les méthodes abstraites définies directement par l'interface ainsi
que les méthodes abstraites héritées de toutes les interfaces
parentes de la sous-interface.
EIA-FR / Jacques Bapst
27
PR1_13
ü La méthode ne peut pas générer plus d'exceptions contrôlées que celles
correspondant à l'intersection de l'ensemble des clauses d'exception
26
EIA-FR / Jacques Bapst
PR1_13
28
Java / Classes abstraites et interfaces
Conflits de noms [2]
• Noms de constantes identiques dans plusieurs interfaces :
ü Doivent être accédées en utilisant la notation qualifiée (Interface.Constante)
• Plusieurs méthodes portent des signatures identiques mais ont des
implémentations par défaut différentes :
ü Erreur détectée par le compilateur
ü Obligation de redéfinir la méthode en conflit dans la classe qui
implémente les interfaces
ü Les méthodes par défaut peuvent malgré tout être invoquée avec la
syntaxe Interface.super.Méthode
EIA-FR / Jacques Bapst
PR1_13
29
Java / Classes abstraites et interfaces
Interface de marquage
§ Il est parfois utile de définir une interface entièrement vide
appelée interface de marquage.
§ Une classe peut implémenter cette interface en la nommant dans
la clause implements sans avoir à implémenter de méthodes.
§ Dans ce cas, toutes les instances de la classe deviennent des
instances valables de l'interface. Il est donc possible de tester
si un objet implémente l'interface de marquage à l'aide de
l'opérateur instanceof :
if (obj instanceof Cloneable) {...}
§ Une interface de marquage sert à communiquer aux instances
qui l'implémentent des informations supplémentaires
concernant l'objet, son comportement, son implémentation, …
§ Les interfaces java.lang.Cloneable et java.io.Serializable
constituent deux exemples d'interfaces de marquage de la plateforme Java.
EIA-FR / Jacques Bapst
PR1_13
30
Java / Classes internes
Classes membres statiques [1]
Informatique / Programmation
§ Une classe membre statique est une classe définie comme un
membre statique d'une autre classe.
§ Des interfaces peuvent également être déclarées comme
membres statiques d'une classe. Les remarques qui suivent
s'appliquent donc également aux interfaces membres statiques.
§ Par analogie avec les méthodes statiques, on pourrait parler de
"classe de classe" (mais cela porte un peu à confusion).
Programmation orientée objet avec Java
14 : Classes internes
§ Une classe membre statique se comporte comme une classe de
premier niveau avec en outre la possibilité d'accéder aux membres
statiques de la classe qui la contient ( classe englobante).
§ Une classe membre statique a accès à tous les membres statiques
de sa classe englobante, y compris les membres privés ( private).
Jacques Bapst
[email protected]
§ L'inverse est également vrai : les méthodes de la classe englobante
ont accès à tous les membres ( statiques ou non-statiques) d'une
classe membre statique, y compris les membres privés.
EIA-FR / Jacques Bapst
Java / Classes internes
PR1_14
Java / Classes internes
Classes internes
Classes membres statiques [2]
§ Jusqu'à présent, les classes (et interfaces) que nous avons vues
étaient toutes des classes (et interfaces) de premier niveau (c'està-dire des membres directs des paquetages, sans imbrication).
§ Une classe membre statique a même accès à tous les membres
des autres classes membres statiques ( classes "sœurs"), y compris
aux membres déclarés private de ces classes.
§ Le langage Java permet cependant de définir des classes à
l'intérieur d'autres classes.
On parle dans ce cas de classes internes (Nested Class).
§ Une classe membre statique peut être déclarée avec ses propres
modificateurs de contrôle d'accès. Ces modificateurs (public,
protected, private, aucun) possèdent les mêmes significations que
pour les autres membres d'une classe (champs et méthodes).
§ Il existe quatre types de classes internes :
Ø Les classes membres statiques
Ø Les classes membres
Ø Les classes locales
Ø Les classes anonymes
§ En dehors de la classe englobante, une classe membre statique
est nommée en combinant le nom de la classe externe avec le
nom de la classe interne. Par exemple :
(Static Nested Class)
(Inner Class)
(Local Inner Class)
LinkedStack.Linkable node
(Anonymous Inner Class)
§ Restrictions :
• Une classe membre statique ne peut pas posséder le même nom
qu'une de ses classes englobantes.
• Une classe membre statique ne peut être englobée que dans une
classe de premier niveau ou dans une classe membre statique.
Attention : D'un auteur à l'autre, le vocabulaire utilisé pour qualifier ces
différentes classes internes peut varier sensiblement.
EIA-FR / Jacques Bapst
3
PR1_14
2
EIA-FR / Jacques Bapst
PR1_14
4
Java / Classes internes
Java / Classes internes
Exemple d'interface membre statique
Classes membres [2]
§ Restrictions :
//===== Une classe qui implémente une pile sous forme de liste chaînée =====
public class LinkedStack {
// Interface membre statique qui définit la manière dont les objets sont liés
public static interface Linkable {
public Linkable getNext();
public void setNext(Linkable node);
}
• Une classe membre ne peut pas porter le même nom qu'une classe ou
qu'un paquetage englobant (une telle restriction ne s'applique pas aux
champs et aux méthodes).
• Les classes membres ne peuvent pas contenir de champs, de
méthodes ou de classe déclarés static (à l'exception des constantes
qui sont déclarées à la fois static et final).
// La tête de liste est un objet de type Linkable
Linkable head;
// Les corps des méthodes sont omis
public void push(Linkable node) { ... }
public Linkable pop() { ... }
§ Pour instancier une classe membre à l'extérieur de la classe de
définition, il faut disposer d'une instance de la classe englobante.
}
§ On utilisera cette instance avec l'opérateur new pour créer un objet
de la classe membre. Syntaxe : InstanceExt.new ClasseInterne
Exemple :
//===== Cette classe implémente l'interface membre statique =====
public class LinkableInteger implements LinkedStack.Linkable {
// Les données et le constructeur du noeud
int i;
public LinkableInteger(int i) { this.i = i; }
ExtClName
// Données et méthodes requises pour implémenter l'interface
LinkedStack.Linkable next;
public LinkedStack.Linkable getNext() { return next; }
public void setNext(LinkedStack.Linkable node) { next = node; }
ExtClName.IntClName iObj = eObj.new IntClName(…);
// Objet externe
// Objet interne
et non pas :
ExtClName.IntClName iObj = eObj.new ExtClName.IntClName(…);
}
EIA-FR / Jacques Bapst
eObj = new ExtClName(…);
PR1_14
EIA-FR / Jacques Bapst
5
Java / Classes internes
PR1_14
Java / Classes internes
Classes membres [1]
Classes membres [3]
§ Une syntaxe particulière est utilisée pour accéder explicitement
aux champs et méthodes d'instance de son objet englobant.
§ Les interfaces ne peuvent pas être déclarées comme membres
non-statiques d'une classe.
§ Cette syntaxe n'est nécessaire que pour référencer un membre
d'une classe englobante qui est masqué par un membre du même
nom dans la classe interne (ce qui est à éviter !) :
Nom_Classe_Englobante . this . Nom_Membre
§ Une instance d'une classe membre est toujours associée à une
instance (un objet) de la classe englobante.
§ Le code d'une classe membre a accès à tous les champs et à
toutes les méthodes (autant statiques que non-statiques et même s'ils
sont déclarés privés) de sa classe englobante et des classes "sœurs".
§ Comme tous les autres membres de la classe, une classe membre
peut être déclarée avec ses propres modificateurs de contrôle
d'accès.
Ces modificateurs (public, protected, private, aucun) possèdent les
mêmes significations que pour les autres membres de la classe
(champs et méthodes).
PR1_14
6
Complément
§ Une classe membre est une classe qui est déclarée comme un
membre non-statique d'une classe englobante.
EIA-FR / Jacques Bapst
7
LinkedStack.this.head
§ Il est également possible d'accéder à un champ masqué ou à une
méthode redéfinie d'une super-classe de la classe englobante :
Nom_Classe_Englobante . super . Nom_Membre
Reactor.super.run()
§ Une classe de premier niveau peut étendre (spécialiser) une
classe membre ce qui introduit deux hiérarchies distinctes ( la
hiérarchie de classes habituelle + une hiérarchie de confinement) qui
affectent les éléments visibles ( portée). ð A éviter !
EIA-FR / Jacques Bapst
PR1_14
8
Java / Classes internes
Java / Classes internes
Exemple de classe membre
Classes locales [2]
§ Les restrictions suivantes s'appliquent aux classes locales :
//===== Une classe qui implémente une pile sous forme de liste chaînée =====
public class LinkedStack {
// Interface membre statique qui définit la manière dont les objets sont liés
public static interface Linkable { ... }
// Contenu omis
• Une classe locale n'est visible qu'au sein du bloc qui la définit; elle ne
peut jamais être utilisée hors de ce bloc.
private Linkable head;
public void push(Linkable node) { ... }
public Linkable pop() { ... }
• Les classes locales ne peuvent pas être déclarées public,
protected, private ou static. Ces modificateurs sont réservés aux
membres de la classe.
// Contenu omis
// Contenu omis
// Cette méthode retourne un objet de type Enumeration pour l'objet LinkedStack courant
public java.util.Enumeration enumerate() { return new Enumerator(); }
}
• Pour les mêmes raisons que les classes membres, les classes locales
ne peuvent pas contenir de champs, de méthodes ou de classes
statiques (à l'exception des constantes déclarées static final).
// Classe membre qui implémente l'interface Enumeration
protected class Enumerator implements java.util.Enumeration {
Linkable current;
// Le constructeur utilise le champ privé head de la classe englobante
public Enumerator() { current = head; }
public boolean hasMoreElements() { return (current != null); }
public Object nextElement() {
if (current==null) throw new java.util.NoSuchElementException();
Object value = current;
current = current.getNext();
return value;
}
}
EIA-FR / Jacques Bapst
• Une classe locale ne peut pas avoir le même nom qu'une de ses
classes englobantes.
• Une classe locale ne peut accéder aux variables locales et
paramètres de méthode qui se trouvent dans sa portée que si ces
variables et paramètres sont déclarés avec le modificateur final.
Dans ce cas, le compilateur créera une copie de ces variables locales
car leur durée de vie peut être plus courte que celle des instances de
la classe locale.
9
PR1_14
EIA-FR / Jacques Bapst
11
Java / Classes internes
Java / Classes internes
Classes locales [1]
Exemple de classe locale
§ Une classe locale est une classe qui est déclarée au sein d'un
bloc de code Java (généralement dans une méthode).
//===== Un exemple de classe locale utilisant des variables locales =====
public class TestLocalClass {
// Interface membre statique
public static interface IntHolder { public int getValue(); }
§ Tout comme une variable locale, une classe locale n'est visible
qu'à l'intérieur du bloc dans lequel elle a été déclarée.
public static void main(String[] args) {
IntHolder[] holders = new IntHolder[10];
§ Les classes locales sont déclarée à l'intérieur d'une classe
englobante et elles partagent de ce fait plusieurs caractéristiques
des classes membres.
for (int i=0; i<10; i++) {
final int fi = i;
// Classe locale pouvant utiliser les variables locales déclarées final
class MyIntHolder implements IntHolder {
public int getValue() { return fi; }
}
holders[i] = new MyIntHolder(); // Instancie la classe locale
}
// La classe locale et la variable fi ne sont plus visibles mais on peut malgré tout utiliser
// le tableau d'instance holders et afficher les valeurs 0…9 (1)
for (int i=0; i<10; i++) System.out.println(holders[i].getValue());
§ Les interfaces ne peuvent pas être déclarées localement.
§ Le code d'une classe locale peut accéder à tous les membres (y
compris aux membres privés) de la classe englobante.
§ Les classes locales peuvent également accéder à toutes les
variables locales et aux paramètres de méthode qui se trouvent
dans la portée de la définition locale de la méthode pour autant
qu'ils soient déclarés final (car la durée de vie d'une instance d'une
classe locale peut être plus longue que l'exécution de la méthode dans
laquelle elle est déclarée).
EIA-FR / Jacques Bapst
PR1_14
PR1_14
10
}
}
(1)
Pour expliquer ce comportement assez surprenant, il faut savoir que chaque instance d'une
classe locale possède une copie privée de chaque variable locale déclarée final qu'elle utilise.
Ainsi, l'instance mémorise l'état des variables qui étaient dans sa portée au moment où elle a
été créée.
EIA-FR / Jacques Bapst
PR1_14
12
Java / Classes internes
Java / Classes internes
Classes anonymes [1]
Classes anonymes [3]
§ Une classe anonyme est une classe locale qui ne possède pas
de nom.
§ Les classes anonymes constituent une forme particulière de
classes locales et toutes les restrictions mentionnées pour les
classes locales s'appliquent également aux classes anonymes.
§ Une classe anonyme est soit :
§ En plus, on peut mentionner la restriction suivante :
• une sous-classe d'une classe parente existante
• Comme les classes anonymes ne possèdent pas de nom, il n'est
pas possible de définir explicitement des constructeurs
(elles possèdent uniquement le constructeur par défaut ).
En remplacement, on peut cependant créer un initialiseur d'instance
qui pourra jouer pratiquement le même rôle qu'un constructeur.
• une classe qui implémente une interface existante
(c'est donc également une sous-classe d'Object)
§ Une classe anonyme combine la déclaration et l'instanciation
de la sous-classe sous la forme d'une expression qui peut
apparaître comme fragment d'une expression plus grande (par
exemple dans une invocation de méthode).
§ Quand utiliser une classe anonyme ?
• La classe possède un corps très court
• Une seule instance de la classe est nécessaire
• Le nom de la classe ne facilite pas la compréhension du code
§ Lorsqu'une sous-classe locale (ou classe implémentant une interface)
n'est utilisée qu'une seule fois, on peut envisager d'en faire une
classe anonyme qui place la définition et l'utilisation de la classe
au même endroit. Cela peut, dans certains cas, favoriser la
compacité et la lisibilité du code source.
EIA-FR / Jacques Bapst
PR1_14
§ Il faut toujours privilégier la lisibilité du code source.
13
Java / Classes internes
EIA-FR / Jacques Bapst
Exemple de classe anonyme
§ La création d'une classe anonyme fait intervenir une nouvelle
syntaxe qui combine la définition et l'instanciation de la classe.
//===== Un exemple de classe anonyme pour filtrer des fichiers dans un répertoire =====
public class TestAnonymousClass {
// Liste tous les fichiers du répertoire D:\Data possédant l'extension .java
public static void main(String[] args) {
§ Pour la définir plus formellement, il faut distinguer les deux
situations possibles.
File f = new File("D:\\Data");
§ Sous-classe anonyme :
Nom_Classe_Parente ( [ Liste_Param ]
15
Java / Classes internes
Classes anonymes [2]
new
PR1_14
// Le répertoire à énumérer
// La méthode list() prend en argument un objet de type FilenameFilter
// Une instance de la sous-classe anonyme de FilenameFilter est créée
// directement dans l'expression d'invocaton de la méthode list()
String[] fileList=f.list( new FilenameFilter() {
) { Corps_Sous_Classe }
public boolean accept(File dir, String s) {
return s.endsWith(".java");
}
§ Classe anonyme implémentant une interface :
new Nom_Interface() { Corps_Classe }
}); // N'oubliez pas la parenthèse et le point-virgule qui achèvent l'appel de la méthode
// Affichage de la liste des fichiers trouvés
for (int i=0; i<fileList.length; i++) {
System.out.println("File name : " + fileList[i]);
}
§ Cette nouvelle syntaxe introduit une complication supplémentaire
sur le plan de la mise en page (indentation) car la création d'une
classe anonyme s'effectue généralement dans le cadre d'une
expression (voir exemple).
ð A utiliser avec modération !
}
}
Noter la mise en page pour l'écriture des classes anonymes (conventions de codage Oracle).
EIA-FR / Jacques Bapst
PR1_14
14
EIA-FR / Jacques Bapst
PR1_14
16
Java / Classes internes
Remarques sur les classes internes [1]
§ Les différents types de classes internes offrent des mécanismes
supplémentaires pour organiser et structurer le code source.
§ En créant une classe interne, on limite leur niveau d'exposition en
les encapsulant au sein d'autres classes. Pour les classes
membres (statiques ou non), on peut limiter leur accès en utilisant
les modificateurs public, protected et private.
§ On peut ainsi retrouver au niveau des classes internes certains
bénéfices de l'encapsulation.
§ Si l'on combine plusieurs niveaux d'imbrication (qui créent une
hiérarchie de confinement) avec une hiérarchie de classes complexe,
on peut très vite arriver à de grandes complications en terme de
portée, visibilité et masquage des identificateurs concernés.
§ Les classes internes ne doivent être utilisées que si elles apportent
des simplifications dans la conception et favorisent la lisibilité et la
maintenance du code. Sinon, elles sont plutôt à éviter.
EIA-FR / Jacques Bapst
PR1_14
17
Java / Classes internes
Remarques sur les classes internes [2]
§ Dans les applications comportant une interface utilisateur
graphique (GUI), les classes internes et plus particulièrement les
classes anonymes sont fréquemment utilisées pour créer, à
la volée, des gestionnaires d'événements (Event Listener).
§ Sur le plan de l'implémentation, les classes internes sont traitées
de la même manière que les classes de premier niveau : chacune
donne lieu à un fichier .class séparé (c'est également vrai pour les
classes anonymes).
§ Suivant les types de classes internes, le nom du fichier résultant
de la compilation est composé de manière différente mais il
comporte généralement le caractère '$' (on trouvera par exemple les
fichiers LinkedStack$Linkable.class ou FilenameFilter$1.class).
§ Lors du déploiement d'une application, il peut être important de
connaître ces détails d'implémentation; par contre, pour l'écriture
d'une application, cela n'a aucune incidence.
EIA-FR / Jacques Bapst
PR1_14
18
Java / Conventions de codage
Pourquoi des conventions de codage ?
Informatique / Programmation
§ Le respect de certaines conventions générales facilite grandement
la lecture du code source :
• Reconnaissance plus rapide de la structure du code
(on se retrouve en terrain connu)
• Identification rapide de certaines entités par leur convention
d'écriture (constantes, classes, …)
Programmation orientée objet avec Java
§ Un code source est écrit une fois et généralement lu à de
nombreuses reprises (parfois longtemps après son écriture et
souvent par des lecteurs différents ).
Il vaut donc la peine d'investir un peu de temps au moment de son
écriture afin de faciliter sa lecture et sa compréhension ultérieure.
15 : Conventions de codage
Jacques Bapst
§ Certains éditeurs offrent des aides pour la mise en page du code
source et le respect de certaines règles de codage.
[email protected]
§ Les conventions proposées par Oracle :
www.oracle.com/technetwork/java/codeconventions-150003.pdf
EIA-FR / Jacques Bapst
Java / Conventions de codage
3
Java / Conventions de codage
Pourquoi des conventions de codage ?
Mise en page
§ Les commentaires doivent être alignés au niveau d'indentation
du code qui suit (pas de commentaires qui brisent la structure du code
en débordant dans la marge d'indentation).
§ Les fichiers sources d'un programme sont destinés à deux types
de lecteurs : l'humain et la machine (le compilateur notamment).
• Pour le compilateur : "a.b(c)"
vaut bien
"myFile.println(currentTime)"
§ Ne pas dépasser (env.) 80 caractères par lignes (pour éviter le
scrolling horizontal et les problèmes d'impression).
§ Les conventions de codage (Style Guidelines) ont pour but
d'améliorer, pour les humains, la lisibilité des fichiers sources
en respectant certaines règles qui ne sont pas imposées par le
langage (choix des identificateurs, mise en page, …).
§ Une seule instruction par ligne (sauf exceptions).
§ Déclarer de préférence les variables locales au début des méthodes.
§ Décomposer le code des méthodes trop longues (celles qui ne
tiennent pas sur une page imprimée ).
§ Il existe des conventions plus ou moins contraignantes.
§ TOUJOURS bien indenter !
§ Un certain nombre de conventions générales (proposées par Sun)
sont adoptées par la très grande majorité des développeurs Java.
• Accolade ouvrante placée en fin de ligne
• Indentation de 2 ou 4 espaces
• Accolade fermante seule sur la ligne et
alignée sur le début de la ligne contenant
l'accolade ouvrante qui lui correspond
§ D'autres (généralement plus contraignantes) sont imposées dans le
cadre de certains projets afin de garantir une certaine homogénéité
des codes sources indépendamment de leur auteur (et assurer une
stabilité dans le temps).
EIA-FR / Jacques Bapst
PR1_15
PR1_15
if (a > b) {
nb = 1;
}
else {
nb = -1;
ok = false;
}
§ Aligner les instructions lorsque cela a un sens (lisibilité).
2
EIA-FR / Jacques Bapst
PR1_15
4
Java / Conventions de codage
Java / Conventions de codage
Commentaires
Choix des identificateurs [1]
§ Pour les commentaires généraux utiliser de préférence la notation
"// texte" (même pour les commentaires qui s'étendent sur plusieurs
lignes).
Type
d'identificateur
Convention de nommage
§ Utiliser la notation "/* texte */" pour inactiver temporairement
une portion de code.
Packages
Uniquement des mots en minuscules séparés com.ibm.javadev
par des points (niveaux hiérarchiques).
ch.eif.project.i02
Si possible, utilisation d'URL inversé.
§ Pour les applications (ou librairies) d'une certaine envergure, des
commentaires de documentation ("/** texte */") devraient
précéder chaque classe et chaque membre public (champs et
méthodes) de la classe.
Classes
Un ou plusieurs noms (substantifs).
Notation Mixed-Case (Camel-Case) avec
première lettre en majuscule.
Raster
StringTokenizer
Interfaces
Un ou plusieurs nom ou adjectifs.
Notation Mixed-Case (Camel-Case) avec
première lettre en majuscule.
Printable
ActionListener
Méthodes
(procédure)
Un verbe (év. avec compléments)
Notation Mixed-Case (Camel-Case) avec
première lettre en minuscule.
runProcess()
draw()
Méthodes
(fonctions)
Un ou plusieurs noms ou noms qualifiés
(éventuellement précédés de get ou is).
Notation Mixed-Case (Camel-Case) avec
première lettre en minuscule.
maxWidth()
isVisible()
§ Pour les exercices, on pourra se contenter d'un en-tête précédant
chaque méthode (au minimum une ligne séparatrice).
§ Inutile d'ajouter des commentaires triviaux :
int counter;
i++;
// Variable compteur
// i = i + 1
EIA-FR / Jacques Bapst
PR1_15
5
Java / Conventions de codage
Exemple
EIA-FR / Jacques Bapst
PR1_15
7
Java / Conventions de codage
Choix des identificateurs [1]
Choix des identificateurs [2]
§ D'une manière générale, les identificateurs doivent être autodescriptifs sans toutefois être trop longs (< ~30 caractères).
Type
d'identificateur
Convention de nommage
Exemple
§ Les variables temporaires peuvent faire exception à cette règle.
Par exemple les compteurs de boucle sont fréquemment déclarés
avec un seul caractère (traditionnellement i, j, k, m, n pour les entiers).
Champs
Variables locales
Paramètres
Un ou plusieurs noms ou noms qualifiés.
Notation Mixed-Case (Camel-Case) avec
première lettre en minuscule.
position
maxSpeed
§ Pour les identificateurs composés de plusieurs mots on adoptera
généralement la notation dite Mixed-Case ou Camel-Case où les
mots sont écrits en minuscules exceptée la première lettre des mots
lors de la transition d'un mot à l'autre (la première lettre du premier mot
pouvant être en majuscule ou en minuscule selon les cas).
Constantes
(static final)
Un ou plusieurs noms ou noms qualifiés.
Mots en majuscules séparés par le caractère
souligné ('_').
PI
MAX_LENGTH
Énumérations
(enum)
Un ou plusieurs noms ou noms qualifiés.
Mots en majuscules séparés par le caractère
souligné ('_').
GREEN
ROTATION_MODE
Types génériques
Une seule lettre, en majuscule.
(<…>)
aMixedCaseIdentifier
SomeOther
<K, V>
§ Dans la notation Mixed-Case on n'utilise généralement pas d'autres
caractères de séparation.
EIA-FR / Jacques Bapst
PR1_15
6
EIA-FR / Jacques Bapst
PR1_15
8