Cours Java1

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

Table des matières

1 Introduction à Java 5
1.1 Comparaison entre Java et C++ . . . . . . . . . . . . . . . . . . . . . . . . 5
1.2 Les points forts de Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.3 Exécution d’un programme Java . . . . . . . . . . . . . . . . . . . . . . . . 7
1.4 Qu’est-ce que le Java Development Kit ? . . . . . . . . . . . . . . . . . . . 8
1.5 Le programme "Bonjour le monde !" . . . . . . . . . . . . . . . . . . . . . 8

2 Eléments de base 10
2.1 Syntaxe Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.1.1 Les identificateurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.1.2 La constante . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.1.2.1 La constante entière . . . . . . . . . . . . . . . . . . . . . 11
2.1.2.2 La constante virgule flottante . . . . . . . . . . . . . . . . 12
2.1.2.3 La constante booléenne . . . . . . . . . . . . . . . . . . . 12
2.1.2.4 La constante caractère . . . . . . . . . . . . . . . . . . . . 12
2.1.2.5 La constante chaîne . . . . . . . . . . . . . . . . . . . . . 12
2.1.3 Les séquences d’échappement . . . . . . . . . . . . . . . . . . . . . 13
2.1.4 Les mots clés . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.1.5 Les commentaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.1.6 Les opérateurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.1.6.1 Opérateurs arithmétiques . . . . . . . . . . . . . . . . . . 15
2.1.6.2 Opérateurs logiques . . . . . . . . . . . . . . . . . . . . . 15
2.1.6.3 Opérateurs de comparaison . . . . . . . . . . . . . . . . . 16
2.1.6.4 Opérateurs d’affectation . . . . . . . . . . . . . . . . . . . 16
2.2 Types de données Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

Mahdi Khemakhem (NAU-IIT 12/13) 1


TABLE DES MATIÈRES

2.2.1 Les variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17


2.2.2 Types de données intégrées . . . . . . . . . . . . . . . . . . . . . . . 17
2.2.2.1 Types de données numériques . . . . . . . . . . . . . . . . 17
2.2.2.2 Types de données booléens . . . . . . . . . . . . . . . . . 18
2.2.2.3 Types de données caractère . . . . . . . . . . . . . . . . . 18
2.2.3 Types de données composites . . . . . . . . . . . . . . . . . . . . . 18
2.2.3.1 Tableaux . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.2.3.2 Chaînes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.2.4 Transtypage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.2.4.1 Transtypage implicite . . . . . . . . . . . . . . . . . . . . 22
2.2.5 Règles de portée . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2.3 Structure de contrôle du déroulement . . . . . . . . . . . . . . . . . . . . . 23
2.3.1 Boucles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
2.3.1.1 La boucle while . . . . . . . . . . . . . . . . . . . . . . . . 24
2.3.1.2 La boucle do . . . . . . . . . . . . . . . . . . . . . . . . . 24
2.3.1.3 La boucle for . . . . . . . . . . . . . . . . . . . . . . . . . 24
2.3.2 Instructions de contrôle des boucles . . . . . . . . . . . . . . . . . . 24
2.3.2.1 L’instruction break . . . . . . . . . . . . . . . . . . . . . . 24
2.3.2.2 L’instruction continue . . . . . . . . . . . . . . . . . . . . 25
2.3.3 Instructions conditionnelles . . . . . . . . . . . . . . . . . . . . . . 25
2.3.3.1 L’instruction if-else . . . . . . . . . . . . . . . . . . . . . . 25
2.3.3.2 L’instruction switch . . . . . . . . . . . . . . . . . . . . . 26

3 Objets, classes 28
3.1 Notion d’objet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
3.1.1 Encapsulation, méthodes et invocation . . . . . . . . . . . . . . . . 30
3.1.2 Niveaux d’abstraction et Classes d’objets . . . . . . . . . . . . . . . 31
3.1.3 Le polymorphisme . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
3.1.4 Pourquoi utiliser l’approche objet ? . . . . . . . . . . . . . . . . . . 33
3.2 Les classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
3.2.1 Déclaration et instanciation des classes . . . . . . . . . . . . . . . . 34
3.2.2 Modificateur d’accès : public . . . . . . . . . . . . . . . . . . . . . . 35
3.2.3 Modificateur d’accès : final . . . . . . . . . . . . . . . . . . . . . . . 35
3.3 Données membre ou attributs . . . . . . . . . . . . . . . . . . . . . . . . . 35

Mahdi Khemakhem (NAU-IIT 12/13) 2


TABLE DES MATIÈRES

3.3.1 Le mot clé : final . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36


3.3.2 Le mot clé : static . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
3.4 Méthodes de classe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
3.4.1 Le mot clé : static . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
3.4.2 Constructeurs et finaliseurs . . . . . . . . . . . . . . . . . . . . . . 38
3.4.3 Exemple simple de définition de classes . . . . . . . . . . . . . . . . 39
3.4.4 Surcharge des méthodes . . . . . . . . . . . . . . . . . . . . . . . . 39
3.5 Les références . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
3.5.1 La création d’objet . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
3.5.2 La référence sur l’objet courant : this . . . . . . . . . . . . . . . . . 42
3.5.3 La référence vide : null . . . . . . . . . . . . . . . . . . . . . . . . . 43
3.5.4 Les opérateurs sur les références . . . . . . . . . . . . . . . . . . . . 44

4 L’héritage 45
4.1 Principes généraux, le mot clé extends . . . . . . . . . . . . . . . . . . . . 45
4.2 Le Polymorphisme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
4.3 Accès à la super-classe d’une classe : super (. . .) . . . . . . . . . . . . . . . 48
4.4 Méthodes et classes abstraites : abstract . . . . . . . . . . . . . . . . . . . 49
4.5 Object : la superclasse cosmique . . . . . . . . . . . . . . . . . . . . . . . . 50

5 Les interfaces 51
5.1 Définitions, les mots clés interface et implements . . . . . . . . . . . . . . 51
5.2 Interface et héritage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
5.3 Les références de type interface, l’opérateur instanceof . . . . . . . . . . . 53

6 Les packages et l’encapsulation 56


6.1 Les packages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
6.2 La structure de stockage des classes et des packages . . . . . . . . . . . . . 57
6.3 Les principaux packages du JDK . . . . . . . . . . . . . . . . . . . . . . . 59
6.4 Les règles de visibilité des attributs et des méthodes . . . . . . . . . . . . 59
6.5 Les classes imbriquées et les classes anonymes . . . . . . . . . . . . . . . 60

7 Les classes de Base 63


7.1 La classe Object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
7.2 Les classes Wrapper . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64

Mahdi Khemakhem (NAU-IIT 12/13) 3


TABLE DES MATIÈRES

7.3 Les chaînes de caractères . . . . . . . . . . . . . . . . . . . . . . . . . . . 66


7.3.1 La classe java.lang.String . . . . . . . . . . . . . . . . . . . . . . . 66
7.3.2 La classe java.lang.StringBuffer . . . . . . . . . . . . . . . . . . . . 67
7.3.3 La classe java.util.StringTokenizer . . . . . . . . . . . . . . . . . . 67
7.4 Les conteneurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
7.4.1 La classe java.util.Vector . . . . . . . . . . . . . . . . . . . . . . . 68
7.4.2 L’interface java.util.Enumeration . . . . . . . . . . . . . . . . . . . 69
7.4.3 La classe java.util.Hashtable . . . . . . . . . . . . . . . . . . . . . 70

Mahdi Khemakhem (NAU-IIT 12/13) 4


Chapitre 1

Introduction à Java

Java est un langage de programmation orientée objet qui est axé sur la création d’objets
qui peuvent être répartis et manipulés par le programme.
Comme d’autres langages de programmation, Java prend en charge la lecture et l’écri-
ture des données dans différents dispositifs d’entrée et de sortie.
Java examine le programme au fil de l’exécution et libère automatiquement la mémoire
qui n’est plus nécessaire. Cela signifie qu’il n’est pas nécessaire de suivre les pointeurs de
mémoire ni de libérer manuellement la mémoire. Cette fonctionnalité évite tout risque de
la mauvaise des pointeurs par les programmeurs.
Les autres langages de programmation sont en général interprétés (Basic ou JavaS-
cript) ou compilés (Pascal ou C). Pour pouvoir être un langage multi-plateforme, Java
est un mélange de ces deux possibilités : les fichiers sources ".java" doivent être compilés
pour fournir un fichier ".class" qui sera interprété. Donc programmer en java suppose que
l’on dispose d’un compilateur et d’un interpréteur java. Ceux-ci sont fournis par le JDK
(Kit de Développement en Java) disponible gratuitement sur le site de la société SUN.

1.1 Comparaison entre Java et C++


Java est très proche du langage C++ étant donné qu’il a quasiment la même syntaxe.
Toutefois Java est plus simple que le langage C++ bien qu’il s’en inspire, car les caracté-
ristiques critiques du langage C++ (celles qui sont à l’origine des principales erreurs) ont
été supprimées. Cela comprend :
– Les pointeurs

Mahdi Khemakhem (NAU-IIT 12/13) 5


1.2 Les points forts de Java

– La surcharge d’opérateurs
– L’héritage multiple
– La libération de mémoire est transparente pour l’utilisateur (il n’est plus nécessaire
de créer de destructeurs)
– Une meilleure gestion des erreurs
– Les chaînes et les tableaux sont des objets faisant partie intégrante du langage
Toutefois Java est beaucoup moins rapide que le langage C++, il perd en rapidité ce
qu’il gagne en portabilité.

1.2 Les points forts de Java


1. Java est robuste
– Compilateur très strict puisqu’il contrôle le typage fort (les pertes de précision
interdites) et vérifie que les erreurs identifiées (appelées exceptions) sont traitées
par le développeur.
– La gestion de la mémoire n’est plus à la charge du développeurs.
– Un débordement d’index dans un tableau provoque une erreur (la mémoire n’est
pas écrasée).
2. Java est portable
– Un code source java est compilé pour générer un code assembleur virtuel : Le
Byte code.
– Le Byte code est exécuté par un logiciel : La machine virtuelle. Elle seule change
d’une machine à l’autre. Un programme Java est donc exécutable sur toute ma-
chine pour laquelle une machine virtuelle existe.
– Le Byte code est conçu pour être rapidement interprété par une machine virtuelle,
pour être optimisant au moment de son exécution.
3. Java est performant
Des techniques récentes d’optimisation et de compilation à la volée du Byte code,
intégrées à certaines machines virtuelles font que ses performances approches celles
de langages compilés.
4. Java est sécurisé
– Limitation des erreurs par la syntaxe.
– Vérification par le compilateur et l’interpréteur.

Mahdi Khemakhem (NAU-IIT 12/13) 6


1.3 Exécution d’un programme Java

5. Java est répartie


Java supporte des mécanismes de communication à distance.
6. Java supporte le multi-threading
– Un Thread est une tâche légère qui partage le même espace de travail que les
autres Threads.
– Lancement de plusieurs Threads au même temps sans blocage.
7. Java est dynamique
Les composants d’une application (classes) sont chargés au lancement de l’applica-
tion.

1.3 Exécution d’un programme Java


Le fichier source d’un programme écrit en Java est un simple fichier texte dont l’ex-
tension est par convention ".java".
Lorsque le programme est prêt à être essayé, il s’agit de le compiler (le traduire en lan-
gage machine) à l’aide d’un compilateur. Toutefois, contrairement aux langages compilés
traditionnels, pour lesquels le compilateur crée un fichier binaire directement exécutable
par un processeur donné (c’est-à-dire un fichier binaire contenant des instructions spé-
cifiques à un processeur), le code source Java est compilé en un langage intermédiaire
(appelé pseudo-code ou Byte code) dans un fichier portant le même nom que le fichier
source à l’exception de son extension ".class".
Cette caractéristique est majeure, car c’est elle qui fait qu’un programme écrit en Java
est portable, c’est-à-dire qu’il ne dépend pas d’une plate-forme donnée. En réalité le code
intermédiaire n’est exécutable sur aucune plate-forme sans la présence d’une machine
virtuelle, un interpréteur (la machine virtuelle est d’ailleurs parfois appelée interpréteur
Java) tournant sur une plate-forme donnée, et capable d’interpréter le code intermédiaire.
Ainsi, chaque plate-forme (Windows 95, Unix, Linux,. . .) qui possède une machine
virtuelle fonctionnant sous son système, celle-ci est capable d’exécuter n’importe quelle
application Java.

Mahdi Khemakhem (NAU-IIT 12/13) 7


1.4 Qu’est-ce que le Java Development Kit ?

1.4 Qu’est-ce que le Java Development Kit ?


Le JDK est l’outil de base pour tout développement Java. Il est disponible gratuitement
au téléchargement sur le site JavaSoft.
Ce kit contient tout le nécessaire pour développer des applications ou des applets
Java : Le compilateur, une machine virtuelle, un ensemble complet de classes de bases
regroupées en packages.

1.5 Le programme "Bonjour le monde !"


Activité 1 : On commence toujours l’étude d’un langage de programmation en écrivant
le programme qui affiche "Bonjour le monde !".
Solution :
Avant de créer ce fichier il est recommandé de créer le dossier de travail qui le contien-
dra. Il suffit ensuite de recopier les lignes qui suivent et d’enregistrer le fichier obtenu dans
le dossier de travail avec le nom "bonjour.java".

/*
Premier programme java : afficher bonjour.
*/
public class bonjour
{
public static void main(String args[])
{
System.out.println("Bonjour le monde !") ;
}
}

Quelques explications
1. Les parties de code situées entre /* et */ sont des commentaires qui ne seront pas
compilés.
2. La première instruction "public class bonjour" déclare qu’on crée une classe publique
(accessible par tous) qui se nomme bonjour. Cette classe doit être enregistrée dans un
fichier de même nom et d’extension ".java". Attention, java différencie les majuscules

Mahdi Khemakhem (NAU-IIT 12/13) 8


1.5 Le programme "Bonjour le monde !"

et les minuscules. La classe bonjour est différente de la classe Bonjour, et le fichier


bonjour.java n’est pas l’équivalent du fichier Bonjour.java.
3. Java étant un langage orienté objet, tout fichier source définit une classe, c’est à
dire un objet possédant des champs et des méthodes. La définition de la classe se
fait dans un bloc d’instructions contenu entre 2 accolades.
4. Notre classe bonjour contient une unique méthode annoncée par l’instruction "public
static void main (String args[])". Il s’agit de la méthode principale d’un programme,
celle qui sera exécutée lors du lancement. Le nom et la déclaration de cette méthode
ne peuvent pas être modifiés.
5. La définition d’une méthode est une suite d’instructions située entre 2 nouvelles
accolades. Dans ce cas, la méthode main n’a qu’une seule instruction qui provoque
l’affichage du message "Bonjour le monde !", par l’intermédiaire de la méthode "Sys-
tem.out.println". Les lignes contenant une instruction simple comme celle-ci doivent
se terminer par un point-virgule.

Mahdi Khemakhem (NAU-IIT 12/13) 9


Chapitre 2

Eléments de base

2.1 Syntaxe Java


La syntaxe d’un langage définit la façon dont le programme est écrit ; plus spécifique-
ment, elle définit les éléments du langage et la façon de les utiliser.

2.1.1 Les identificateurs


Un identificateur est un nom qui identifie de façon unique une variable, une méthode
ou une classe. Les restrictions de Java relatives aux identificateurs sont les suivantes :
– Tous les identificateurs doivent commencer par une lettre, un trait de soulignement
(_) ou un signe dollar ($).
– Un identificateur peut inclure des chiffres, mais ne doit pas commencer par un chiffre.
– Un identificateur ne peut pas contenir d’espace vide (tabulation, espace, nouvelle
ligne ou retour chariot).
– Les identificateurs différencient les minuscules et les majuscules.
– Les mots clés de Java ne peuvent pas servir d’identificateurs.
A coté de ces restrictions, certaines conventions s’appliquent aux identificateurs pour
faciliter leur lecture. Le tableau suivant donne la liste de ces conventions selon le type
d’identificateur :

Mahdi Khemakhem (NAU-IIT 12/13) 10


2.1 Syntaxe Java

Type d’identificateur Convention Exemples


Nom de classe Chaque mot commence par Mammifère,MammifèreMarin
une majuscule
Nom de fonction Chaque mot, sauf le pre- obtenirAge, définirHauteur
mier, commence par une
majuscule
Nom de variable Chaque mot, sauf le pre- age, tailleCerveau
mier, commence par une
majuscule
Noms des constantes Toutes les lettres sont en MAX_HEIGHT,
majuscules et les mots sont MAX_AGE
séparés par un trait de sou-
lignement

Table 2.1 – La liste des conventions selon le type d’identificateur

2.1.2 La constante
Un littéral, ou constante, représente une valeur qui ne change jamais. Par exemple,
le nombre 35 est un littéral or l’identificateur "age" représente un nombre qui peut être
égal à 35. Dans Java, une constante peut être un nombre (entier ou virgule flottante), un
booléen, un caractère ou une chaîne.

2.1.2.1 La constante entière

Les constantes entières peuvent prendre trois formats : décimal (base 10), hexadécimal
(base 16) et octal (base 8).
– Les constantes décimales sont écrites comme des nombres ordinaires,
– Les constantes hexadécimales commencent toujours par 0X,
– Les constantes octales commencent par 0.
Par exemple, le nombre décimal 10 s’écrit 0xA ou 0XA en format hexadécimal et 012
en format octal. Une constante entière peut être stockée dans les types de données byte,
short, int ou long.

Mahdi Khemakhem (NAU-IIT 12/13) 11


2.1 Syntaxe Java

Pour stocker une constante entière dans le type de données long, qui peut recevoir des
valeurs de 64 bits, il faut ajouter le caractère l ou L à la fin du littéral. Par exemple, la
constante 9999L est stockée dans le type long. Les lignes de code suivantes utilisent des
littéraux entiers :
int x = 12345 ; //12345 est un littéral
int y = x * 4 ; //4 est un littéral

Dans la première ligne, la constante 12345 est stockée directement dans la variable x de
type int. Dans la deuxième ligne, la constante 4 sert à calculer une valeur qui est ensuite
stockée dans la variable y de type int.

2.1.2.2 La constante virgule flottante

Une constante virgule flottante est un nombre contenant un point décimal et/ou un
exposant. Une constante virgule flottante suit une notation standard ou scientifique. Par
exemple, 123.456 est la notation standard, alors que 1.23456e+2 est la notation scienti-
fique.
Les constantes virgules flottantes sont du type double sur 64 bits (type par défaut) ou du
type float sur 32 bits. Pour stocker une constante virgule flottante dans le type float, on
ajoute la lettre f ou F à la fin du nombre.

2.1.2.3 La constante booléenne

Une constante booléenne représente deux états possibles : vrai ou faux. Les constantes
booléennes sont stockées dans le type de données booléen. Java représente les états d’une
valeur booléenne par les mots clés true (vrai) et false (faux).

2.1.2.4 La constante caractère

Les constantes caractères sont toujours mises entre guillemets simples ; par exemple,
’A’ et ’9’ sont des constantes caractère. Java utilise le type char pour stocker des caractères
uniques.

2.1.2.5 La constante chaîne

Une constante chaîne représente une suite de caractères. Dans Java, les chaînes sont
toujours entre guillemets doubles. Java utilise les classes String et StringBuffer pour repré-

Mahdi Khemakhem (NAU-IIT 12/13) 12


2.1 Syntaxe Java

senter les chaînes. Ainsi, de tous les types de constante dont on a parlé, seuls les constantes
chaîne sont stockées par défaut sous forme d’objets.

2.1.3 Les séquences d’échappement


Une séquence d’échappement est un type spécial de constante caractère. Java utilise
les séquences d’échappement pour représenter des caractères de contrôle spéciaux et des
caractères non imprimables. Une séquence d’échappement est représentée par une barre
oblique inversée (\) suivie d’un code caractère. Le tableau suivant résume ces séquences
d’échappement :
Caractères Séquence d’échappement
Barre oblique inversée \\
Retour arrière \b
Retour chariot \r
Continuation \
Guillemet double \"
Saut de page \f
Tabulation horizontale \t
Nouvelle ligne \n
Guillemet simple \’

Table 2.2 – Les séquences d’échappement


Pour illustrer l’utilisation des séquences d’échappement, la chaîne de l’instruction suivante
imprime sur la première ligne les mots Nom et ID séparés par deux tabulations et, sur la
deuxième ligne, "Jean Martin" et "999" également séparés par deux tabulations :

String d = new String ("Nom\t\t ID\n\"Jean\Martin\"\t\t\"999\"") ;


On remarque que cette instruction est intentionnellement écrite sur deux lignes ; en consé-
quence, le caractère de continuation (\) évite toute erreur du compilateur.

2.1.4 Les mots clés


Un mot clé est un identificateur prédéfini qui a une signification spéciale pour le
compilateur Java et qui ne peut pas être redéfini. Voici la liste des mots clés Java :

Mahdi Khemakhem (NAU-IIT 12/13) 13


2.1 Syntaxe Java

abstract boolean break byte


byvalue* case cast* catch
char class const* continue
default do double else
extends false final finally
float for future* generic*
goto* if implements import
inner* instanceof int interface
long native new null
operator* outer* package private
protected public rest* return
short static super switch
synchronized this throw throws
transient true try var*
void volatile while

Table 2.3 – Les mots réservés


* Réservé mais non utilisé.
Comme l’on remarque, les mots clés sont toujours écrits en minuscules. De façon générale,
les mots clés Java peuvent être classés par catégories selon leurs fonctions de la façon
suivante (exemples entre parenthèses) :
– Mots clés de déclaration des données (boolean, float, int)
– Mots clés de boucle (continue, while, for)
– Mots clés conditionnelles (if, else, switch)
– Mots clés d’exception (try, throw, catch)
– Mots clés de structure (class, extends, implements)
– Mots clés de modification et d’accès (private, public, transient)
– Mots clés divers (true, null, super)

2.1.5 Les commentaires


Les commentaires sont des instructions écrites en langage naturel par le programmeur
pour ajouter des remarques concernant le code.

Mahdi Khemakhem (NAU-IIT 12/13) 14


2.1 Syntaxe Java

Dans Java, il y a trois styles de commentaires. Le premier commence par /* et se termine


par */ Le deuxième style de commentaire ressemble au premier mais commence par /**et
se termine par */. Le troisième style de commentaire commence par // et ne peut être
écrit que sur une ligne.

2.1.6 Les opérateurs


Les opérateurs sont des symboles spéciaux qui exécutent une fonction particulière
sur des opérandes. Il y a cinq types généraux d’opérateurs : opérateurs arithmétiques,
opérateurs logiques, opérateurs de comparaison, opérateurs d’affectation et opérateurs
au niveau bits. Chaque catégorie peut être subdivisée en unaire et binaire. Les opéra-
teurs unaires utilisent un seul opérande, alors que les opérateurs binaires utilisent deux
opérandes.

2.1.6.1 Opérateurs arithmétiques

Java fournit un jeu complet d’opérateurs destinés aux calculs arithmétiques. A la


différence de certains langages, Java peut exécuter des fonctions mathématiques à la fois
sur des valeurs entières et en virgule flottante.
Opérateur Définition Préséance Associativité
++/- - Incrémentation/décrémentation 1 Droite
automatique
+/- Plus/moins unaire 2 Droite
* Multiplication 4 Gauche
/ Division 4 Gauche
% Modulo 4 Gauche
+/- Addition/soustraction 5 Gauche

Table 2.4 – La liste des opérateurs mathématiques

2.1.6.2 Opérateurs logiques

Les opérateurs logiques (ou booléens) permettent au programmeur de regrouper des


expressions booléennes pour déterminer certaines conditions. Ces opérateurs exécutent les
opérations booléennes standards(AND, OR, et NOT).

Mahdi Khemakhem (NAU-IIT 12/13) 15


2.1 Syntaxe Java

Opérateur Définition
! Complément logique unaire
(NOT)
&& Court-circuit AND
|| Court-circuit OR

Table 2.5 – La liste des opérateurs logiques

2.1.6.3 Opérateurs de comparaison

Les programmeurs ont besoin de comparer des valeurs. A la différence des opérateurs
logiques, les opérateurs de comparaison n’évaluent qu’une seule expression.
Opérateur Définition Préséance Associativité
< (resp >) Inférieur à (resp Supérieur à ) 7 Gauche
<= (resp >=) Inférieur (resp Supérieur) ou égal 7 Gauche
à
== Egal à 8 Gauche
!= Différent de 8 Gauche

Table 2.6 – La liste des opérateurs de comparaison

2.1.6.4 Opérateurs d’affectation

Comme tous les langages, Java permet d’attribuer des valeurs aux variables.
Opérateur Définition Préséance Associativité
= Affectation 15 Droite
+= Ajout et affectation 15 Droite
-= Soustraction et affectation 15 Droite
*= Multiplication et affectation 15 Droite
/= Division et affectation 15 Droite
&= AND avec affectation 15 Droite
|= OR avec affectation 15 Droite
∧= XOR avec affectation 15 Droite

Mahdi Khemakhem (NAU-IIT 12/13) 16


2.2 Types de données Java

Table 2.7 – La liste des opérateurs d’affectation

2.2 Types de données Java


Dans Java, il y a deux catégories de types de données : intégrés et composites. Les types
de données intégrés (ou primitifs) peuvent ensuite être divisés en trois autres catégories :
numérique, booléen et caractère. Ils sont compris par le compilateur et ne nécessitent pas
de bibliothèques spéciales. Les types composites sont de deux sortes : tableaux et chaînes.
Généralement, les types composites nécessitent l’utilisation de bibliothèques spéciales.
Avant d’étudier les différents types de données de Java, on doit en savoir plus sur les
variables.

2.2.1 Les variables


Pour affecter de la mémoire au stockage de types de données, il faut d’abord déclarer
une variable du type de données voulu, puis lui donner un nom (identificateur) qui la
référence. Voici la syntaxe générale d’une déclaration de variable :

typeDonnées identificateur [ = valeurParDéfaut ] ;

La déclaration commence par le type de la variable, puis désigne l’identificateur et se


termine par l’affectation facultative d’une valeur par défaut. Voici quelques exemples de
déclarations de variables de différents types :

int p ; //déclare la variable p à stocker dans le type de données int


float x, y = 4.1, z = 2.2 ;
boolean finDeFichier = false ;
char car1 = ’T’ ;
Une variable peut être déclarée n’importe où dans un programme, tant que sa déclaration
précède les instructions qui y font référence. Java est un langage forcé, ce qui signifie que
toutes les variables doivent être déclarées avant d’être utilisées.

2.2.2 Types de données intégrées


2.2.2.1 Types de données numériques

Le tableau suivant résume les types de données numériques :

Mahdi Khemakhem (NAU-IIT 12/13) 17


2.2 Types de données Java

Types Taille Description (valeurs extrêmes)


byte 8 bits très petit nombre entier signe (-128 ⇒127)
short 16 bits nombre entier signe court (-32768 ⇒ 32767)
int 32 bits nombre entier signe (-2.14e+9 ⇒ 2.14e+9)
long 64 bits nombre entier signe long (-9.22e+18 ⇒ 9.22e+18)
float 32 bits nombre en virgule flottante (1.402e-45 ⇒ 3.402e+38)
double 64 bits nombre en virgule flottante (4.94e-324 ⇒ 1.79e+308)

Table 2.8 – La liste des types de données numériques

Si le programmeur n’initialise pas une variable numérique, la machine virtuelle Java lui
donne automatiquement la valeur 0. La plupart des compilateurs Java détectent les va-
riables non initialisées.

2.2.2.2 Types de données booléens

Un type de données booléen a deux valeurs : true et false. Java utilise le type de
données intégré boolean. Les variables de type boolean non initialisées ont automa-
tiquement la valeur false. Le code suivant illustre l’utilisation d’une variable de type
boolean :
int a = 1, b = 0 ;
boolean bool = a < b ; //bool a la valeur false

2.2.2.3 Types de données caractère

Java utilise le type de données char pour stocker un caractère Unicode unique. Le
type char de Java a une largeur de 16 bits.

2.2.3 Types de données composites


2.2.3.1 Tableaux

Un tableau est une structure de données qui peut contenir plusieurs éléments de même
type. Les éléments d’un tableau peuvent être de n’importe quel type : type primitif, type
composite ou classe définie par l’utilisateur. Voici quelques exemples de déclarations de
tableaux :

Mahdi Khemakhem (NAU-IIT 12/13) 18


2.2 Types de données Java

int idEtudiant[] ;
char[] grades ;
float coordonnées[][] ;
Ces déclarations amènent deux remarques :
1. La taille du tableau n’est pas précisée ; dans la plupart des langages, la taille d’un
tableau doit faire partie de sa déclaration.
2. Les crochets peuvent suivre l’identificateur, comme dans le premier exemple, ou
suivre le type de données, comme dans le deuxième exemple.

Création et initialisation des tableaux Les déclarations de tableaux ci-dessus n’af-


fectent pas réellement de mémoire aux tableaux (elles déclarent simplement des identi-
ficateurs qui permettront éventuellement de stocker des tableaux réels). C’est la raison
pour laquelle les tailles des tableaux ne sont pas précisées. Pour affecter réellement de la
mémoire aux variables tableaux, il faut utiliser l’opérateur new de la façon suivante :

int idEtudiant[] = new int[20] ;


char[] grades = new char[20] ;
float[][] coordonnées = new float[10][5] ;
La première instruction crée un tableau de 20 éléments de type int, la deuxième crée un
tableau de 20 éléments de type char et la troisième crée un tableau à deux dimensions 10
sur 5 de type float (10 lignes, 5 colonnes). Quand un tableau est créé, tous ses éléments
sont vides.
Pour initialiser un tableau, les valeurs des éléments du tableau sont énumérées à l’in-
térieur d’un ensemble entre accolades. Pour les tableaux à plusieurs dimensions, il faut
utiliser des accolades imbriquées. Les instructions suivantes illustrent cette initialisation :

char[] grades = ’A’, ’B’, ’C’, ’D’, ’F’ ;


float[][] coordonnées = {0.0, 0.1}, {0.2, 0.3} ;
La première instruction crée un tableau de type char appelé grades. Elle initialise les
éléments du tableau avec des valeurs comprises entre ’A’ et ’F’. On n’a pas eu besoin
d’utiliser l’opérateur new pour créer ce tableau ; en initialisant le tableau, la mémoire
nécessaire est automatiquement affectée au tableau pour y mettre les valeurs inutilisées.
Par conséquent, la première instruction crée un tableau de type char de 5 éléments. La
deuxième instruction crée un tableau de type float a deux dimensions appelé coordonnées,

Mahdi Khemakhem (NAU-IIT 12/13) 19


2.2 Types de données Java

avec une taille de 2 sur 2. La première ligne du tableau est initialisée avec les valeurs 0.0
et 0.1 et la deuxième ligne avec les valeurs 0.2 et 0.3. De par sa conception, coordonnées
est un tableau contenant deux éléments tableau.

Accès aux éléments des tableaux Pour accéder aux éléments d’un tableau, il faut
indexer la variable tableau. Cette indexation implique que le nom de la variable tableau
soit suivi du numéro de l’élément (index) entre crochets. L’index des tableaux commence
toujours à 0. Dans le cas d’un tableau à plusieurs dimensions, il faut utiliser un index par
dimension. Voici quelques exemples :

premierElément = grades[0] ; //premierElément = ’A’


cinquièmeElément = grades[4] ; //cinquièmeElément = ’F’
ligne2Col1 = coordonnées[1][0] ; //ligne2Col1 = 0.2

La petite partie de code suivante illustre l’utilisation des tableaux. Elle crée un tableau
de 5 éléments de type int appelé tableauInt, puis utilise une boucle for pour mettre les
nombres entiers 0 à 4 dans les éléments du tableau :
int[] tableauInt = new int [5] ;
int index ;
for (index = 0 ; index < 5 ; index++)
tableauInt [index] = index ;

Les boucles for sont présentées dans une section ultérieure. Ce code utilise la boucle pour
incrémenter la variable index de 0 à 4 et, à chaque passage, la valeur de index est mise
dans l’élément de tableauInt indexé par index.

2.2.3.2 Chaînes

Une chaîne est une suite de caractères. Pour stocker des chaînes, Java utilise le type
String. Ce type de données fait partie du paquet java.lang. Cela signifie qu’il ne s’agit
pas d’un type intégré ; pour déclarer une variable du type String, il faut utiliser le paquet
java.lang.
Une fois initialisée, une variable de type String ne peut pas être modifiée. Comment
peut-elle être une variable et ne pas pouvoir être modifiée ? On rappelle qu’une variable
n’est qu’une référence à un emplacement en mémoire ; on l’utilise pour accéder à la mé-
moire sur laquelle elle pointe et modifier cette mémoire. Dans le cas d’une variable du

Mahdi Khemakhem (NAU-IIT 12/13) 20


2.2 Types de données Java

type String, la mémoire sur laquelle pointe la variable String ne peut pas être modifiée ;
toutefois, la variable elle-même peut pointer ailleurs, comme l’illustre le code suivant :

String s = new String ("Bonjour") ;


s = "Bonjour à tous" ; //s pointe maintenant sur un nouvel emplacement mémoire
On a d’abord créé une variable de type String appelée s qui pointait sur un emplacement
particulier en mémoire contenant la chaîne "Bonjour ". Avec la deuxième ligne, s pointe
sur un nouvel emplacement en mémoire qui contient maintenant "Bonjour à tous". Cela
est exact puisque on a modifié la variable elle-même, et non la mémoire sur laquelle elle
pointe. Cela illustre la différence entre une variable et la mémoire sur laquelle elle pointe.
Pour disposer d’un meilleur contrôle sur les chaînes, on utilise la classe StringBuffer.
Cette classe, qui fait aussi partie du paquet java.lang, fournit des méthodes permettant
de modifier le contenu des chaînes. Voici un exemple impossible à réaliser avec la classe
String :

StringBuffer s = new StringBuffer ("Bonjour") ;


s.setCharAt (1, ’e’) ; //s a maintenant la valeur "Benjour"

La méthode setCharAt() de StringBuffer remplace le caractère situé à la position


précisée par le premier paramètre par le caractère donné en second paramètre.

2.2.4 Transtypage
Dans certains cas, il est nécessaire de convertir un type de variable en un autre type.
Par exemple, on peut avoir besoin de transmettre une variable de type int à une méthode
qui n’accepte que des variables de type float. Convertir le type d’une variable s’appelle
transtypage. Pour transtyper une variable, on précède l’identificateur de la variable du
type voulu entre parenthèses. L’exemple suivant montre comment la variable renvoyée
par une méthode, de type int, peut être transtypée en type float :

float f = (float) retourInt() ;

Il faut être prudent lors des transtypages, car il y a des risques de perte d’informations.
Par exemple, lors d’un transtypage d’une variable de type long de 64 bits en une variable
de type int de 32 bits, le compilateur ignore les 32 bits de niveau supérieur de la variable
de type long. Si la valeur de la variable de type long dépasse 32 bits au moment du
transtypage, le transtypage attribue une valeur inexacte à la variable de type int.

Mahdi Khemakhem (NAU-IIT 12/13) 21


2.2 Types de données Java

En règle générale, le type cible du transtypage doit avoir une taille au moins égale au
type initial. Le tableau suivant montre les transtypages qui ne risquent pas de provoquer
des pertes d’informations :

Type initiale Transtypage


byte short, char, int, long, float,
double
short int, long, float, double
char int, long, float, double
int long, float, double
long float, double
float double

Table 2.9 – Tableau de transtypage

2.2.4.1 Transtypage implicite

Dans certains cas, un transtypage peut être réalisé implicitement par le compilateur.
Voici un exemple :

if (3 > ’a’) {}

Dans ce cas, la valeur ’a’ est convertie en un nombre entier (valeur ASCII de la lettre a)
avant d’être comparée au nombre 3.

2.2.5 Règles de portée


Les règles de portée déterminent où est reconnue une variable dans un programme.
Les variables appartiennent à deux catégories de portée principales :
1. Variables globales : Variables reconnues tout au long du programme.
2. Variables locales : Variables reconnues uniquement dans le bloc de code où elles sont
déclarées.
Les règles de portée sont étroitement liées aux blocs de code. Voici la règle de portée
générale : une variable déclarée dans un bloc de code n’est visible que dans ce bloc et
dans les blocs qui y sont imbriqués.

Mahdi Khemakhem (NAU-IIT 12/13) 22


2.3 Structure de contrôle du déroulement

Le code suivant illustre cette règle :

class démoPortée
{
int x = 0 ;
void méthode1()
{
int y ;
y = x ; //correct
}
void méthode2()
{
int z = 1 ;
z = y ; //incorrect !
}
}

Ce code déclare une classe appelée démoPortée qui contient deux méthodes : méthode1 ()
et méthode2(). La classe elle-même est considérée comme étant le bloc de code principal
et les deux méthodes sont ses blocs imbriqués.
La variable x est déclarée dans le bloc principal et elle est donc visible (reconnue par le
compilateur) dans la méthode méthode1() et la méthode2(). D’autre part, les variables y
et z sont déclarées dans deux blocs imbriqués mais indépendants ; ainsi, essayer d’utiliser
y dans méthode2 () provoque une erreur, puisque y n’est visible que dans son bloc.

2.3 Structure de contrôle du déroulement


2.3.1 Boucles
Dans un programme, chaque instruction est exécutée une fois. Cependant, il est quel-
quefois nécessaire d’exécuter une ou plusieurs instructions plusieurs fois jusqu’à ce qu’une
condition soit satisfaite. Avec Java, il y a trois façons de créer des boucles : boucles while,
do et for.

Mahdi Khemakhem (NAU-IIT 12/13) 23


2.3 Structure de contrôle du déroulement

2.3.1.1 La boucle while

La boucle while est utilisée pour créer un bloc de code qui sera exécuté tant qu’une
condition particulière est satisfaite.

Voici la syntaxe générale de la boucle while :

while (condition) {
code à exécuter dans une boucle
}

2.3.1.2 La boucle do

La boucle do ressemble à la boucle while, sauf qu’elle évalue la condition après les
instructions et non avant. Voici la syntaxe générale de la boucle do :

do {
code à exécuter dans une boucle
}while(condition) ;

2.3.1.3 La boucle for

La boucle for est la plus puissante des constructions de boucles. Voici la syntaxe
générale d’une boucle for :

for (expr init ; expr condition ; expr opération) {}

L’initialisation d’une boucle for se compose de trois parties : une expression d’initialisa-
tion, une expression conditionnelle et une expression d’opération. La troisième expression
met généralement à jour la variable de la boucle initialisée par la première expression.

2.3.2 Instructions de contrôle des boucles


2.3.2.1 L’instruction break

L’instruction break permet de sortir d’une structure de boucle avant que la condition
du test soit respectée. Quand la boucle rencontre une instruction break, elle se termine
immédiatement en ignorant le code restant. En voici un exemple :

Mahdi Khemakhem (NAU-IIT 12/13) 24


2.3 Structure de contrôle du déroulement

int x = 0 ;
while (x < 10)
{
System.out.println("Bouclage") ;
x++ ;
if (x == 5)
break ;
else
//faire quelque chose d’autre
}

Dans cet exemple, la boucle s’arrête quand x est égal à 5.

2.3.2.2 L’instruction continue

L’instruction continue permet d’ignorer le reste de la boucle et de reprendre l’exécution


à l’itération suivante de la boucle.
for ( int x = 0 ; x < 10 ; x++)
{
if(x == 5)
continue ; //revient au début de la boucle avec x=6
System.out.println("Bouclage") ;
}

Cet exemple n’imprime pas "Bouclage" si x a la valeur 5.

2.3.3 Instructions conditionnelles


Avec les instructions conditionnelles, Le code a la possibilité de prendre des décisions.
Dans Java, il y a deux structures conditionnelles : l’instruction if-else et l’instruction
switch.

2.3.3.1 L’instruction if-else

Voici la syntaxe de l’instruction if-else :

Mahdi Khemakhem (NAU-IIT 12/13) 25


2.3 Structure de contrôle du déroulement

if (condition1)
{//blocCode 1}
else if (condition2)
{//blocCode 2}
else
{//blocCode 3}
L’instruction if-else est généralement constituée de plusieurs blocs. Quand l’instruction
if-else s’exécute, un seul des blocs est exécuté (celui dont la condition a la valeur true,
évidemment). Les blocs if-else et le bloc else sont facultatifs. L’instruction if-else n’est
pas limitée à trois blocs, elle peut contenir autant de bloc if-else que nécessaire.

2.3.3.2 L’instruction switch

D’une certaine façon, l’instruction switch est une version spécialisée de l’instruction
if-else. Voici la syntaxe générale de l’instruction switch :
switch (expression)
{
case valeur1 : blocCode1 ;
break ;
case valeur2 : blocCode2 ;
break ;
default : blocCode3 ;
}
Il faut éclaircir un certain nombre de points concernant l’instruction switch :
– Les blocs de code n’ont pas besoin d’être mis entre accolades.
– Le bloc de code default correspond au bloc else d’une instruction if-else.
– Les blocs de code sont exécutés selon la valeur d’une variable ou d’une expression,
pas d’une condition.
– La valeur de l’expression doit être de type nombre entier (ou d’un type qui peut
être transtypé en int sans risque, comme char).
– Les valeurs case doivent être des expressions constantes du même type que l’expres-
sion.
– Le mot clé break est facultatif. Il est nécessaire pour terminer l’exécution de l’ins-
truction switch une fois qu’un code de bloc s’exécute. Si, par exemple, break n’est

Mahdi Khemakhem (NAU-IIT 12/13) 26


2.3 Structure de contrôle du déroulement

pas mis après blocCode1 et si blocCode1 est exécuté, alors blocCode2 s’exécute im-
médiatement après blocCode1 (un effet secondaire parfois utile mais, dans la plupart
des cas, indésirable).
– Si un bloc de code doit être exécuté quand l’expression a une valeur parmi plusieurs,
il faut énumérer les valeurs-chacune étant précédée d’un mot clé case et suivie par
un point-virgule.

Mahdi Khemakhem (NAU-IIT 12/13) 27


Chapitre 3

Objets, classes

Java est un langage orienté Objet. L’approche Objet est, en programmation, une
approche fondamentalement différente de l’approche procédurale abordée avec un langage
tel que le C :
– Dans une approche procédurale, il y a séparation complète des notions de Données
et d’Actions (de code) : le développeur part des données (de quoi dispose-t’on, que
veux t’on obtenir), pour ensuite définir la série des actions qui permettent de trans-
former les données initiales en résultats souhaités. Ces actions sont décomposées de
manière hiérarchique (une action d’un certain niveau est la composition d’actions
du niveau inférieur). Ce qui permet d’obtenir un certain niveau d’organisation et de
réutilisation (les procédures ou fonctions).

Figure 3.1 – Approche procédurale


– Dans l’approche Objet, il n’y a plus séparation des données et des actions : Le
travail du développeur consiste à faire interagir des objets qui contiennent chacun

Mahdi Khemakhem (NAU-IIT 12/13) 28


3.1 Notion d’objet

les données permettant de représenter un élément logique de programmation, ainsi


que les méthodes qui constituent le seul moyen d’agir sur ces données. Dans un
programme objet, on dit qu’il y a coopération entre les objets qui le composent :
chaque objet peut invoquer une méthode d’un autre objet qui coopère en répondant
à cette demande. Chaque objet est lui-même la composition d’un ensemble d’objets
coopératifs.

Figure 3.2 – Approche Objet

3.1 Notion d’objet


C’est une notion très proche de celle de la vie courante : On représente en permanence
le monde sous la forme d’un ensemble d’objets plus ou moins abstraits, avec lesquels on
interagit et qui interagissent entre eux : des tables, des stylos, des personnes, des animaux
...
La vision qu’on a d’un certain objet peut être différente en fonction des besoins, c’est
à dire en fonction du problème que l’on a à résoudre, du mécanisme que l’on doit décrire :
– Un policier dont le rôle est de régler la circulation voit un ensemble de véhicules,
objets interagissant entre eux, qui doivent respecter des règles de circulation et qu’il
peut à volonté faire stopper ou faire circuler. De son point de vue, un camion ou
une voiture sont des objets de même nature.
– Le conducteur d’un de ces véhicules, le voit d’un autre oeil : Il conduit une voiture
bien particulière, et il dispose d’un ensemble complexe de commandes pour la faire
avancer, la diriger, interagir avec les autres véhicules. Son problème à lui est de se
déplacer d’un point à un autre, si possible rapidement.

Mahdi Khemakhem (NAU-IIT 12/13) 29


3.1 Notion d’objet

– Un garagiste, connaît les différentes pièces qui composent un véhicule, ainsi que son
fonctionnement interne : pour lui un véhicule est lui-même un ensemble d’objets
interagissant entre eux.
– Le concepteur du véhicule, intervient à un niveau de décomposition encore plus bas :
Il peut par exemple se pencher sur la structure atomique de tel matériau utilisé dans
la construction de son véhicule pour des raisons de solidité de celui-ci.
On voit à travers cet exemple, que parler de l’objet véhicule représente un certain
niveau d’abstraction : on fait abstraction de la réalité pour s’intéresser à un niveau de
représentation de cet objet suffisant pour permettre de résoudre le problème : il peut être
intéressant de descendre dans le détail (la voiture, les pièces composant une voiture,. . .),
mais on ne le fera que si cela est nécessaire (si le problème change et par conséquent on
doit changer de niveau d’abstraction). Le policier et le conducteur de l’exemple précédent
n’ont pas du tout la même vision du même objet.
Un objet est défini par la manière dont on peut interagir avec lui et cela en fonction
du problème que l’on a à résoudre. Il représente un tout logique du point de vue du
problème qu’en s’intéresse : peu importe ses composants et la manière dont il fonctionne
exactement, peu importe s’il peut faire autre chose si cela est utile. Il correspond à un
certain niveau d’abstraction de la réalité et il est représenté essentiellement par les services
qu’il peut rendre.

3.1.1 Encapsulation, méthodes et invocation


Du point de vue de celui qui l’utilise, un objet est une boite noire qui offre un certain
nombre de fonctions ou méthodes permettant d’interagir avec lui. Peu importe comment
il est construit de manière interne, la seule chose nécessaire pour pouvoir utiliser un objet
est savoir ce qu’il peut faire et surtout, comment lui demander.
Exemple : Un poste de Télévision est une boite ayant pour interface : un écran, des haut-
parleurs et une télécommande. Pour changer de chaîne il suffit de demander à cette boite
noire de le faire, en appuyant simplement sur le bouton correspondant. Peu importe ce
qui se passe réellement dans le poste.
L’ensemble des méthodes proposées par un objet est appelé l’interface de cet objet.
On dit qu’un objet est encapsulé par son interface : la seule manière d’interagir avec cet
objet est d’invoquer une des méthodes de son interface. Peu importe de quoi cet objet

Mahdi Khemakhem (NAU-IIT 12/13) 30


3.1 Notion d’objet

est réellement constitué, ce qui est important c’est les services (les méthodes) qu’il peut
fournir.

Figure 3.3 – Un Objet

L’encapsulation d’un objet par son interface permet de masquer son contenu et donc offre
la possibilité de modifier celui-ci sans aucun impact pour le reste du monde. Respecter ce
principe d’encapsulation, permet aussi de pouvoir utiliser immédiatement des objets de
même nature, même si leur fonctionnement interne est différent.
Cela constitue un des points centraux de l’approche objet : Pour respecter ce principe
d’encapsulation on ne doit interagir avec un objet que par l’invocation d’une des méthodes
de son interface. En faisant cela on dit à l’objet ce qu’il doit faire, jamais comment il doit
le faire.
Par exemples :
– Lorsque l’on freine avec sa voiture on se contente d’appuyer sur la pédale de frein
(on invoque la méthode de freinage), on ne s’occupe pas de savoir s’il s’agit d’un
frein à disque ou de la manière dont cette commande est transmise
– Un policier qui règle la circulation, invoque la méthode " arrêter " à un véhicule en
levant la main d’une certaine manière. Il ne s’occupe pas de la manière dont chaque
véhicule s’arrête.

3.1.2 Niveaux d’abstraction et Classes d’objets


Plusieurs niveaux d’abstractions sont possibles lorsqu’on représente un certain objet
"réel " : Lorsqu’on regarde la table qui est dans la cuisine, on fait généralement abstraction
de tout ce qui compose physiquement cet objet (pieds de fer, plateau, tiroir,. . .) pour ne
voir que l’objet de la cuisine permettant de ranger les couverts et de servir de support

Mahdi Khemakhem (NAU-IIT 12/13) 31


3.1 Notion d’objet

pour le repas. En fait, on range alors implicitement cette table dans l’ensemble général des
tables de cuisine. Cet ensemble regroupe tous les objets ayant les mêmes fonctionnalités
que la table. En langage objet on parle de la Classe des tables de cuisines et on dit que la
table de cuisine particulière est une instance de cette classe (C’est à dire un représentant
de cette classe).
Une classe est définie en décrivant l’interface commune à tous les objets qui la com-
posent (qui sont des instances de celle-ci).
Si on cherche un support pour écrire une lettre, on cherchera de manière plus générale
une table permettant de fournir le service " support ". On pourra choisir la table de la
cuisine, du salon ou de la table à manger. La classe des tables de cuisine est donc comprise
dans celle plus générale des tables (qui inclut aussi la classe des tables de salon,. . .). La
classe des tables est un niveau d’abstraction supérieur à celle des tables de cuisine :
elle représente un ensemble d’objets moins spécialisés que la classe des tables de cuisine.
Une table de cuisine est une table qui possède des caractéristiques spécifiques. On dit
que la classe des tables de cuisine est une classe fille de la classe des tables et qu’elle
hérite des caractéristiques de cette classe, tout en la spécialisant par l’ajout de nouvelles
fonctionnalités. Si la classe des tables est déjà définie, et si on veut définir celle des tables
de cuisine, il suffira de dire que cette nouvelle classe hérite de la précédente, avec en plus,
telle ou telle nouvelle caractéristique.
Une classe fille est définie à partir de sa mère par héritage (réutilisation de ce qui est
déjà défini) et spécialisation (ajout de nouvelles fonctionnalités).
En fonction des besoins et du moment, on pourra considérer la table, soit comme une
table de cuisine pour ranger des couverts, soit comme une table de salon pour ranger des
trucs de décoration, soit comme une table quelconque pour écrire une lettre.

Figure 3.4 – Un diagramme de classes

Mahdi Khemakhem (NAU-IIT 12/13) 32


3.1 Notion d’objet

3.1.3 Le polymorphisme
Le polymorphisme (du grec " plusieurs formes "), signifie que la même méthode peut
être définie dans différentes classes et que chaque classe peut implémenter (réaliser) cette
méthode à sa manière. Il est ainsi parfaitement possible d’invoquer une méthode sur un
objet sans savoir à quelle classe celui-ci appartient exactement et donc sans savoir quelles
seront exactement les actions réalisées.
Par exemples :
– Lorsque l’on freine dans une voiture on sait que la fonction attendue est de stopper le
véhicule. En fonction du type réel de véhicule (de sa classe plus spécifique) les actions
réelles seront très différentes (ABS ou non, freins à tambour, électromagnétiques,. . .).
Le conducteur n’a pas besoin de connaître ce niveau de détail pour savoir s’arrêter.
– Un policier qui règle la circulation invoque toujours la même méthode pour arrêter
des objets de la classe des véhicules. Chaque véhicule, en fonction de sa classe
spécifique utilisera cependant une méthode particulière pour s’arrêter : un cycliste
ne s’arrêtera pas comme une voiture ou un camion. . .

3.1.4 Pourquoi utiliser l’approche objet ?


La motivation essentielle de cette approche est d’augmenter les possibilités de réutili-
sation de ce qu’on développe : Le monde de la programmation est encore proche du stade
artisanal où chaque programmeur passe son temps à redévelopper ce que d’autres ont déjà
réalisé.
Les moyens de réutilisation offerts par l’approche objet sont multiples :
– L’encapsulation des données et du code dans une même entité permet de garantir la
cohérence des objets. Cette cohérence est indispensable pour envisager de réutiliser
un objet dans un autre contexte.
– La notion d’encapsulation par une interface permet de normaliser le fonctionnement
des objets : il est possible de changer le fonctionnement interne d’un objet particulier,
sans modifier la manière de l’utiliser.
– La notion d’héritage permet de réutiliser ce qui a déjà été défini lors de la conception
d’un objet pour en créer de nouveaux.
– La notion de polymorphisme, permet de manipuler de manière identique des objets
ayant des comportements totalement différents.

Mahdi Khemakhem (NAU-IIT 12/13) 33


3.2 Les classes

De manière plus générale, l’approche objet permet de construire des programmes mieux
conçus, plus évolutifs et souvent plus sûrs.

3.2 Les classes


Tout d’abord, il faut faire la distinction entre les classes et les objets. Une classe est
la définition d’un type, alors que l’objet est une déclaration de variable. Après avoir créé
une classe, on peut créer autant d’objets basés sur cette classe.
Le processus de création d’un objet à partir d’une classe est appelé instanciation d’un
objet ou création d’une occurrence d’une classe.

3.2.1 Déclaration et instanciation des classes


Une classe Java peut être très simple. Voici la définition d’une classe vide :

class MaClasse { }

Évidemment, cette classe n’est pas encore utile, mais elle est correcte dans Java. Une classe
un peu plus utile contiendra quelques données membres et des méthodes. On commence
par étudier la syntaxe de l’instanciation d’une classe. Pour créer une occurrence de cette
classe, il faut utiliser l’opérateur new avec le nom de la classe. Il faut déclarer une variable
d’occurrence pour l’objet.

MaClasse monObjet ;

Mais cette instruction n’affecte ni mémoire ni autres ressources à l’objet. Elle crée une
référence appelée monObjet, mais n’instance pas l’objet. C’est le rôle de l’opérateur new.

monObjet = new MaClasse() ;

On remarque que le nom de la classe est utilisé comme s’il s’agissait d’une méthode. Il
ne s’agit pas d’une coïncidence. Après l’exécution de cette ligne de code, il est possible
d’accéder aux variables et aux méthodes membres de la classe avec l’opérateur ".". Une
fois l’objet créé, on n’a pas à se préoccuper de sa destruction. Dans Java, les objets sont
automatiquement éliminés par le Garbage collector. Dès que la référence à un objet (c’est-
à-dire la variable) sort de la portée, la machine virtuelle libère automatiquement toutes
les ressources affectées par l’opérateur new.

Mahdi Khemakhem (NAU-IIT 12/13) 34


3.3 Données membre ou attributs

3.2.2 Modificateur d’accès : public


Une classe est soit publique, soit privée :
– Une classe publique est visible en dehors du Package dans lequel elle est définie
– Une classe privée n’est pas visible en dehors de ce Package.
Un Package est un regroupement logique de classes (de fichiers contenant des classes). Par
défaut une classe est privée et dans un fichier Java, il ne peut y avoir qu’une seule classe
publique : Si deux classes publiques sont définies dans un seul fichier il y a une erreur à
la compilation, sachant qu’une classe est publique si sa définition est précédée du mot clé
public.

public class MaClasse { }

3.2.3 Modificateur d’accès : final


Une classe définie comme final ne peut pas être dérivée (on ne peut pas créer une
nouvelle classe héritant de cette classe). Ce modificateur est utile pour des raisons de
sécurité et de performances.
public final class MaClasse
{. . .}
class SaClass extends MaClass {. . .}
// => Erreur de compilation

3.3 Données membre ou attributs


Une classe Java peut contenir des données membre et des méthodes. Voici une classe
qui ne contient que des données membres :
public class ClasseChien
{
String nom,couleurYeux ;
int age ;
boolean avecQueue ;
}
Dans cet exemple, on a créé la classe ClasseChien qui contient des variables membre
appelées nom, couleurYeux, age et un indicateur appelé avecQueue. Une variable membre

Mahdi Khemakhem (NAU-IIT 12/13) 35


3.4 Méthodes de classe

d’une classe peut avoir n’importe quel type (primitif, composite et types d’objets). Pour
accéder à une donnée membre, il faut d’abord créer une occurrence de la classe puis
accéder aux données avec l’opérateur ".".

3.3.1 Le mot clé : final


Le mot clé final, utilisé pour un attribut, permet de spécifier que cet attribut est une
constante (sa valeur ne pourra jamais être modifiée). Un attribut final doit obligatoirement
être initialisée lors de sa déclaration.

3.3.2 Le mot clé : static


Le mot clé static, utilisé pour un attribut, permet d’indiquer que cet attribut est
commun à tous les objets de la classe concernée : il s’agit d’un attribut de la classe elle-
même, et si on modifie cet attribut pour un objet donné, il sera modifié pour tous les
objets de la classe.

public class ClasseChien


{
String nom,couleurYeux ;
int age ;
boolean avecQueue ;
static int count = 0 ;
ClasseChien() { count++ ; }
}
...
ClasseChien v1 = new ClasseChien() ;// count=1
ClasseChien v2 = new ClasseChien() ;//count=2
...

3.4 Méthodes de classe


Les classes peuvent contenir aussi des méthodes. En fait, il n’y a dans Java ni fonction
ni procédure autonome, ils sont définies en tant que méthodes de classes. Voici un exemple
de la classe ClasseChien ci-dessus à laquelle est ajoutée la méthode aboie() :

Mahdi Khemakhem (NAU-IIT 12/13) 36


3.4 Méthodes de classe

public class ClasseChien


{
String nom,couleurYeux ;
int age ;
boolean avecQueue ;
public void aboie()
{
Message msgAboie = new Message() ;
msgAboie.setMessage( "Wouah, wouah" ) ;
}
}

On remarque que, lors de la définition des méthodes, l’implémentation de la méthode


figure juste sous la déclaration. Cela est différent de certains autres langages orientés
objet dans lesquels la classe est définie à un emplacement et le code d’implémentation est
situé ailleurs. On remarque aussi qu’il faut spécifier un type de retour et les paramètres
reçus par la méthode. L’accès à une méthode est similaire à l’accès aux variables membre.
Par exemple,

ClasseChien chien = new ClasseChien() ;


chien.age = 4 ;
chien.aboie() ;

3.4.1 Le mot clé : static


Il est possible de définir une méthode de type "static". De même que pour les attributs,
cela signifie que les actions de cette méthode concernent la classe entière (pas un objet
particulier). Pour cette raison, une méthode statique, ne peut accéder qu’aux attributs
statiques de la classe : lorsqu’on utilise une telle méthode, vouloir accéder à un attribut
appartenant à un objet particulier n’a pas de sens.
On peut invoquer une méthode statique soit sur la classe elle-même, soit sur un objet
de cette classe. Dans tous les cas elle s’appliquera sur la classe entière.
L’utilisation d’une méthode statique ne nécessite pas la construction d’un objet ap-
partenant à la classe correspondante.

Mahdi Khemakhem (NAU-IIT 12/13) 37


3.4 Méthodes de classe

class MathTool {
final static double PI = 3.14 ;
static double getPI() { return PI ; }
static double diametre( double rayon ) { return 2*PI*rayon ;
}
static double power(double x) { return x * x ; }
}
class Test {
void methode1() {
double i = MathTool.power(6) ;
}
}

Cet exemple présente une utilisation classique des méthodes static, à savoir une classe
rassemblant un ensemble d’outils sur un certain sujet.

3.4.2 Constructeurs et finaliseurs


Chaque classe a une méthode spéciale appelée constructeur, qui porte toujours le même
nom que la classe et ne peut pas préciser de valeur de retour. Le constructeur prend soin
d’affecter toutes les ressources dont l’objet a besoin et de renvoyer une occurrence de
l’objet. Quand on utilise l’opérateur new, on appelle en réalité le constructeur. Comme
l’occurrence de l’objet est toujours le type de retour, il n’est pas nécessaire de préciser de
type de retour du constructeur !
Dans la plupart des langages orientés objet, une méthode nommée destructeur, est
appelée pour libérer les ressources affectées par le constructeur. Cependant, comme on
l’a déjà signalé, Java n’a pas de mécanisme destructeur, puisque ce langage prend soin de
libérer toutes les ressources.
Cependant, certaines situations nécessitent un nettoyage spécial que le Garbage col-
lector ne peut pas effectuer quand la classe disparaît. Par exemple, certains fichiers ont
été ouverts pendant la durée de vie de l’objet et on veut vérifier qu’ils sont correctement
fermés quand l’objet est détruit. Pour cela, une autre méthode spéciale, appelée finali-
seur, peut être définie. Cette méthode est appelée par le Garbage collector immédiatement
avant la destruction de l’objet. Ainsi, si un nettoyage spécial quelconque doit avoir lieu,
le finaliseur peut le faire.

Mahdi Khemakhem (NAU-IIT 12/13) 38


3.4 Méthodes de classe

3.4.3 Exemple simple de définition de classes


Voici le contenu du fichier ClasseChien.java :

public class ClasseChien


{
String nom,couleurYeux ;
int age ;
boolean avecQueue ;
public ClasseChien()
{
nom = "Snoopy" ;
couleurYeux = "Noir" ;
age = 2 ;
avecQueue = true ;
}
}

Voici la source de ClasseHomme (trouvée dans ClasseHomme.java) :

public class ClasseHomme


{ String nom,couleurYeux ;
int age ;
boolean estMarié ;
public ClasseHomme()
{
nom = "Bob" ;
couleurYeux = "Bleu" ;
age = 1 ;
estMarié = true ;
}
}

3.4.4 Surcharge des méthodes


Dans Java, il est possible de créer dans une classe plusieurs méthodes qui portent le
même nom mais avec différents paramètres et/ou valeurs de retour. Cela est connu sous le

Mahdi Khemakhem (NAU-IIT 12/13) 39


3.4 Méthodes de classe

nom de surcharge des méthodes. Java décide la méthode à appeler en regardant la valeur
de retour et les paramètres.

class Test {
void print(int i) {. . .}
void print(float f) {. . .}
void print(int i, int j) {. . .}
}
...
Test t = new Test() ;
int i ;
t.print( i ) ; // => La première méthode est appelée

A l’appel, la machine virtuelle Java détermine quelle est la méthode dont la lise de pa-
ramètres est la plus proche des paramètres effectivement envoyés. Dans le cas d’un appel
de méthode avec des types ne correspondants pas exactement, des transtypages implicites
peuvent être effectuées.

short s ;
t.print( s ) ;// => La première méthode est appelée avec une conversion de s en int

Dans le cas où plusieurs méthodes pourraient correspondre, la machine virtuelle va déter-


miner pour chacune d’entre elles le coût des conversions nécessaires à partir du tableau
suivant. Elle choisira ainsi la méthode correspondante au plus faible coût.
Si le coût global des conversions des paramètres passés dépasse 10, le compilateur
refusera l’appel. Il faudra alors expliciter cette conversion.

Table 3.1 – Le coût de transtypage

Mahdi Khemakhem (NAU-IIT 12/13) 40


3.5 Les références

3.5 Les références


Les références sont les variables qui permettent de désigner et manipuler les objets. La
notion de référence est assez proche de celle de pointeur, mais, contrairement au langage
C, il n’est pas possible de manipuler directement l’adresse contenue dans ces pointeurs :
cela est donc moins souple, mais beaucoup plus simple et sécurisant qu’un vrai pointeur.

3.5.1 La création d’objet


La création d’un objet se fait à l’aide de l’opérateur new qui se charge de :
1. Allouer l’espace mémoire nécessaire pour stocker les attributs de l’objet en cours de
construction
2. Appeler le constructeur de l’objet adéquat pour initialiser les attributs. Le choix du
constructeur se fait en fonction des paramètres passés à l’opérateur new (mêmes
règles que pour la surcharge des méthodes normales)
3. Retourner une référence sur l’objet créé
Les références doivent être considérées comme des pointeurs intelligents sur les objets
alloués dynamiquement par l’opérateur new : il est possible de copier une référence, et
donc de disposer à un instant t de plusieurs références sur un même objet ; Le nombre
de référence sur un même objet est mémorisé en permanence dans un compteur ; lorsque
celui-ci tombe à zéro, la mémoire est automatiquement libérée par le Garbage Collector.

Mahdi Khemakhem (NAU-IIT 12/13) 41


3.5 Les références

Figure 3.5 – Exemple de références

Le Garbage Collector est un outil très puissant pour gérer les problèmes de mémoires en
Java. Il est en particulier impossible d’utiliser de la mémoire non libérée et donc d’écraser
la mémoire.

3.5.2 La référence sur l’objet courant : this


Le mot-clé this représente une référence sur l’objet courant (celui qui est en train
d’exécuter la méthode dans laquelle se trouvent les instructions concernées).
this peut être utile :
– Lorsqu’une variable locale (ou un paramètre) cache un attribut de la classe
– Pour déclencher un constructeur depuis un autre constructeur

Mahdi Khemakhem (NAU-IIT 12/13) 42


3.5 Les références

class Date {
int jour =1 ;
int mois =1 ;
int an =1990 ;
Date( ) { an = 2000 ; } /* peut aussi s’écrire : this.an = 2000 */
Date( int an ) {this.an = an ;} /* Le paramètre an cache l’attribut an */
Date( int jour, int mois, int an )
{
this.jour = jour ;
this.mois = mois ;
this(an) ; /* appel du deuxième constructeur */
}
}

3.5.3 La référence vide : null


Le mot clé null permet de représenter la référence qui ne référence rien. On peut
assigner cette valeur à n’importe quelle variable ou attribut contenant une référence.
C’est la valeur par défaut d’initialisation des attributs représentant des références et
on peut tester si une référence est égale à null.

Class Test {
Voiture v1 ; /* Initialisée à null par défaut */
void methode()
{
...
if ( v1 == null ) v1 = new Voiture("Volvo") ;
...
}
}

Si une méthode est invoquée sur une référence égale à null, cela déclenche une erreur du
type NullPointerException.

Mahdi Khemakhem (NAU-IIT 12/13) 43


3.5 Les références

3.5.4 Les opérateurs sur les références


Les seuls opérateurs sur les références sont des opérateurs logiques :

==
: permet de tester si deux références désignent le même
objet.
!=
: permet de tester si deux références ne désignent pas le
même objet.
instanceof
: permet de tester si l’objet référencé est une instance d’une
classe donnée ou d’une de ses sous-classes

Mahdi Khemakhem (NAU-IIT 12/13) 44


Chapitre 4

L’héritage

En Java, il est possible de dériver une classe à partir d’une autre classe : la classe fille
ainsi créée (ou sous-classe, ou classe dérivée) hérite alors des caractéristiques de sa classe
mère (ou super-classe), tout en la spécialisant avec de nouvelles fonctionnalités.

4.1 Principes généraux, le mot clé extends


Toute classe dans Java est une sous classe de la classe Object (elle en hérite directement
ou indirectement et éventuellement implicitement).
Une classe ne peut hériter directement que d’une seule classe : il n’y a pas d’héritage
multiple dans Java. Cette caractéristique du langage permet de supprimer de nombreux
problèmes liés à l’héritage multiple. Il est cependant possible d’avoir autant de niveau
d’héritage que voulu : une classe peut avoir une mère, une grand-mère, une arrière-grand-
mère, etc.
Une sous-classe peut redéfinir une ou plusieurs méthodes dont elle hérite. Bien entendu,
elle peut aussi en définir de nouvelles, ainsi que de nouveaux attributs.
Il est possible d’interdire qu’une classe puisse être héritée : il suffit de déclarer cette
classe final (déjà vu dans le chapitre précédent). Il est possible d’interdire qu’une méthode
soit redéfinie dans une sous-classe : il suffit de déclarer cette méthode final.
Le mot clé extends permet de décrire les relations d’héritage : pour créer une nouvelle
classe fille, il suffit de déclarer cette classe en faisant suivre son nom du mot clé extends
puis du nom de sa classe mère. Voici un exemple classique de hiérarchie de classes :

Mahdi Khemakhem (NAU-IIT 12/13) 45


4.1 Principes généraux, le mot clé extends

class Felin {
boolean afaim = true ;
void parler() { }
void appeler() {
System.out.println("Le Félin est appelé") ;
if (afaim) parler() ;
}
}
final class Chat extends Felin {
String race ;
void parler() { System.out.println("miaou !") ; }
}
final class Tigre extends Felin {
void parler() { System.out.println("Groar !") ; }
void chasser() { . . .}
}
...
Tigre tigre = new Tigre() ;
tigre.chasser() ; // OK
tigre.appeler() ; // OK : méthode héritée de la classe Felin

Les classes Chat et Tigre héritent de la classe Felin, ce qui signifie que les instances
de Chat et Tigre seront aussi des Félins. En particulier, les deux classes filles héritent
de l’attribut afaim, et des méthodes parler() et appeler(). De plus, la class Felin n’a
explicitement aucune classe mère. Elle hérite donc implicitement de la classe Object.
Les classes Chat et Tigre ont été déclarées final : on ne pourra pas définir de nouvelle
classe héritant d’une de ces classes.
On remarque dans chaque classe fille que la méthode parler() est redéfinie et que de
nouveaux attributs et méthodes sont définis (race, chasser()). Les attributs d’une classe
dérivée comprennent les attributs hérités et les attributs propres (idem pour les méthodes).
Une variable qui référence un objet d’une certaine classe peut référencer un objet de
n’importe laquelle de ses sous-classes (un objet membre d’une sous-classe est aussi membre
de la super-classe) : c’est le cas ici pour la variable qui référence un objet de type Felin
qui peut donc contenir la référence sur un Tigre

Mahdi Khemakhem (NAU-IIT 12/13) 46


4.2 Le Polymorphisme

Felin felin ;
Tigre tigre = new Tigre() ;
felin = tigre ;
felin.parler() ;//c’est la méthode Tigre.parler() qui est réellement appelée
felin.chasser() ; // Erreur à la compilation : La méthode n’existe pas dans la classe
Felin
tigre = felin ; // Erreur à la compilation : Conversion explicite nécessaire
tigre = (tigre)felin ; // OK
tigre.parler() ; // OK
tigre.chasser() ; // OK
Chat chat = new Chat() ;
felin = chat ;
lion = (lion)felin ; // Erreur détectée lors de l’exécution : ClassException

Le fait de déclencher la méthode parler() sur la référence de type Felin, déclenche en fait
la méthode de la classe Tigre. C’est un des grands avantages des langages orientés objets :
la méthode est exécutée par l’objet réel se trouvant au bout de la référence et lorsqu’on
demande à un Tigre de parler, il le fait comme on le lui a appris, même si celui qui fait
la demande ne sait pas exactement qu’il est un Felin. Cette capacité de Java s’appelle le
polymorphisme.

4.2 Le Polymorphisme
Une méthode polymorphe est une méthode déclarée dans une super-classe et redéfinie
par une sous-classe. Dans Java, toute méthode est par défaut polymorphe. Les méthodes
final ne peuvent pas être redéfinies et ne sont pas polymorphes (définir une méthode final
est utile pour optimiser le Byte code et pour des raisons de sécurité).
L’intérêt des méthodes polymorphes est que lorsqu’on les appelle, la version qui est
exécutée est toujours celle correspondant à l’objet réel se trouvant au bout de la référence
utilisée, même si la nature de cet objet réel n’est pas connue au moment de l’appel.

Mahdi Khemakhem (NAU-IIT 12/13) 47


4.3 Accès à la super-classe d’une classe : super(. . .)

class Zoo {
int MAX ;
Felin[] liste ;
Int compteur = 0 ;
Zoo( int taille ) { MAX = taille ; liste = new Felin[MAX] }
void addFelin( Felin newfelin) {
if (compteur < MAX) liste[compteur++] = newfelin ;
else /* traitement d’erreur */
}
final void appeler() { // cette méthode ne peut être redéfinie dans une sous-classe
for ( int i=0 ; i<compteur ; i++ ) liste[i].parler() ; // appel polymorphe
}
}
...
Zoo zoo = new Zoo(10) ;
zoo.addFelin(new Tigre()) ;
zoo.addFelin(new Chat()) ;
zoo.appeler() ;. . .

Cet exemple montre une mise en oeuvre simple du polymorphisme. La méthode parler()
a été redéfinie dans toutes les sous-classes de la classe Felin. Lorsqu’on demande à chacun
des félins de l’application d’exécuter la méthode parler(), c’est à chaque fois une méthode
différente qui est déclenchée.

4.3 Accès à la super-classe d’une classe : super (. . .)


Le mot clé super permet d’accéder à la version non redéfinie des attributs et méthodes
de la super-classe. Il permet aussi, s’il est utilisé comme première instruction dans un
constructeur, d’appeler un des constructeurs de la classe mère, avec ou sans paramètres.

Mahdi Khemakhem (NAU-IIT 12/13) 48


4.4 Méthodes et classes abstraites : abstract

class Mere {
int attribut ;
Mere() { attribut = 1 ; }
Mere(int attribut) { this.attribut = attribut ;}
void print() { System.out.println("base" + attribut) ;}
}
class Fille extends Mere {
boolean flag ;
Fille( int a ) {
super(a) ;
flag = true ;
}
void print() {
super.print() ;
System.out.println("dérivée") ;
}
} ...
Fille f = new Fille(2) ;
Mere m = f ;
m.print() ;
// Affiche :
base 2
dérivée

4.4 Méthodes et classes abstraites : abstract


Une méthode abstraite est une méthode dont on donne le prototype, sans en décrire
l’implémentation (sans définir les instructions qui décrivent ses actions). Elle doit, de
plus, être précédée du mot clé abstract. Une méthode abstraite doit obligatoirement être
redéfinie dans une sous-classe pour pouvoir être utilisée (par polymorphisme).
Une classe abstraite est une classe dont la définition est précédée du mot clé abstract.
Une classe abstraite ne peut jamais être directement instanciée avec l’opérateur new pour
créer un nouvel objet : seules des classes filles non abstraites peuvent l’être.
Lorsqu’une classe possède une ou plusieurs méthodes abstraites, elle doit elle-même être

Mahdi Khemakhem (NAU-IIT 12/13) 49


4.5 Object : la superclasse cosmique

déclarée abstraite, mais la réciproque n’est pas vraie : une classe peut être abstraite sans
pour autant posséder de méthode abstraite.
Les classes et les méthodes abstraites permettent de définir des fonctionnalités, sans
spécifier la façon dont ces fonctionnalités sont implémentées. Une classe héritant d’une
classe abstraite doit donner une implémentation à toutes les méthodes abstraites de sa
super-classe. Si ce n’est pas le cas, elle doit aussi être déclarée abstraite.
abstract class Felin {
boolean afaim = true ;
abstract void parler( ) ;
void appeler() {
System.out.println("Le Félin est appelé") ;
if (afaim) parler() ;
}
}
class Tigre extends Felin {
void parler() { System.out.println("Groar !") ; }
}

4.5 Object : la superclasse cosmique


La classe Object représente le dernier ancêtre (ancêtre ultime). Toutes les classes Java
héritent d’Object.Néanmoins, on n’écrit jamais :
class Employee extends Object
La superclasse Object est prise en compte par défaut si aucune superclasse n’est expli-
citement spécifiée. Comme chaque classe Java dérive de Object, il est important de se
familiariser avec les fonctionnalités de cette classe ancêtre.
Une variable de type Object peut référencer un objet de n’importe quel type :
Object obj = new Employee("Harry Hacker", 35000) ;
Bien entendu, une variable de type Object n’est utile qu’en tant que conteneur générique
pour des valeurs arbitraires. Pour pouvoir réellement en utiliser la valeur courante, il faut
connaître le type original (effectif) et appliquer un transtypage :
Employee e = (Employee) obj ;

Mahdi Khemakhem (NAU-IIT 12/13) 50


Chapitre 5

Les interfaces

Fonctionnellement, une interface ressemble à une classe abstraite mais avec une dif-
férence importante : une interface ne peut pas inclure de code. Dans Java, le mécanisme
d’interface est un moyen destiné à remplacer l’héritage multiple.

5.1 Définitions, les mots clés interface et implements


Une interface est une déclaration permettant de décrire un ensemble de méthodes
abstraites et de constantes. On peut considérer une interface comme étant une classe
abstraite ne contenant que des méthodes abstraites et que des attributs final et static.
Il est donc impossible d’instancier directement une interface. Par contre, une classe
peut implémenter une ou plusieurs interfaces, en utilisant le mot clé implements suivi du
nom de chaque interface concernée. Cette classe doit alors fournir une version pour chaque
méthode déclarée dans les interfaces implémentées. On peut considérer l’implémentation
des interfaces comme une forme d’héritage multiple léger.
Une interface est définie de manière similaire à une classe, mais elle est caractérisée
par le mot clé interface.

Mahdi Khemakhem (NAU-IIT 12/13) 51


5.2 Interface et héritage

interface Printable
{void print() ;}
class Point extends Object implements Printable
{private double x,y ;
...
void print()
{System.out.println( "(" + x + "," + ")" ) ;}
}

La notion d’interface permet de mieux découpler l’implémentation d’un objet de la vision


que les autres objets peuvent en avoir : une classe peut implémenter plusieurs interfaces,
c’est à dire rendre plusieurs types de service (ceux définis au niveau de chaque interface).
Réciproquement, la même interface peut être implémentée par plusieurs classes : chaque
objet de ces classes fournit donc le même type de service (celui défini dans l’interface).
On verra qu’il est possible de manipuler des références correspondant à une certaine
interface, et donc de manipuler des objets à travers ces références en ayant uniquement
la connaissance qu’ils implémentent cette interface.
Les attributs déclarés dans une interface sont obligatoirement des constantes statiques :
les mots clés static et final ne sont pas nécessaires pour le préciser. Ces attributs doivent
donc obligatoirement être initialisés.

interface Interval
{ int MIN = 0 ;
int MAX = 1000 ;
}
...
for (int i = Interval.MIN ; i < Interval.MAX ; i++ ) {. . .}
...

5.2 Interface et héritage


On a déjà annoncé qu’une classe peut implémenter plusieurs interface. Une interface
peut aussi hériter d’une ou plusieurs interfaces : elle hérite alors de l’ensemble des mé-
thodes abstraites et constantes de ses ancêtres.

Mahdi Khemakhem (NAU-IIT 12/13) 52


5.3 Les références de type interface, l’opérateur instanceof

interface Printable
{ /* exprime le fait de pouvoir être imprimé */
void print() ;
}
interface InputStream
{ /* exprime le fait de pouvoir être une source de caractères */
public int read() ;
}
interface OutputStream
{ /* exprime le fait de pouvoir accepter des caractères */
public void write(int) ;}

interface DataStream extends InputStream, OutputStream


{ public double readDouble() ;
public void writeDouble(double) ;
}
class MonStream implements DataStream, Printable
{ void print() {. . .}
public int read() {. . .}
public void write(int) {. . .}
public double readDouble(){. . .}
public void writeDouble(double) {. . .}
}

5.3 Les références de type interface, l’opérateur ins-


tanceof
Une interface définie un nouveau type : il est possible de définir des références du type
d’une interface, c’est à dire permettant de référencer des objets dont tout ce que l’on sait
est qu’ils implémentent cette interface.
Des objets complètement différents peuvent donc être référencés et utilisés de la même
manière à condition qu’ils implémentent la même interface : c’est une généralisation du
polymorphisme et de ses avantages. L’exemple suivant met en oeuvre le polymorphisme
au travers de l’utilisation d’une interface. Cette interface définie un service (Persistent)

Mahdi Khemakhem (NAU-IIT 12/13) 53


5.3 Les références de type interface, l’opérateur instanceof

qui est implémenté par un certain nombre de classes de l’application (la classe Client
dans l’exemple). On stocke une collection d’objet implémentant le service Persistent dans
un tableau de type Persistent. Chacun de ces objets dispose donc de la méthode save(),
avec sa propre implémentation. La classe PersistentManager peut alors manipuler tous
ces objets avec l’interface Persistent, sans rien savoir de leur nature réelle.
interface Persistent
{void save() ; }
class Client extends Personne implements Persistent
{ private int numero ;
...
public void save()
{ /* Enregistrement sur fichier ou Base de donnée */ }
}

class PersistentManager
{ private final static int MAX=100 ;
private static Persistent[] liste_des_objets = new Persistent[MAX] ;
static int nb = 0 ;
...
public static void addPersistent(Persistent objet)
{if (nb<MAX) liste_des_objets[nb++] = objet ;}
public static void saveAll ()
{
for (int i=0 ; i<liste_des_objets.length ; i++)
if ( liste_des_objets[i] != null ) liste_des_objets[i].save() ;
}
}
...
Client client = new Client("Toto",4529) ;
PersistentManager.addPersistent(client) ;
...
PersistentManager.saveAll() ;

L’opérateur instanceof peut être utilisé pour savoir si un objet implémente une interface
donnée :

Mahdi Khemakhem (NAU-IIT 12/13) 54


5.3 Les références de type interface, l’opérateur instanceof

Point point = new Point() ;


...
if ( point instanceof Printable ) ((Printable)point).print() ;
...

Mahdi Khemakhem (NAU-IIT 12/13) 55


Chapitre 6

Les packages et l’encapsulation

Pour faciliter la réutilisation du code, Java permet de regrouper plusieurs définitions


de classes dans un groupe logique appelé package. Si, par exemple, on crée un groupe
des règles de gestion qui modélisent les traitements de gestion d’une entreprise, on peut
les réunir dans un paquet. Cela facilite la réutilisation du code précédemment créé.

6.1 Les packages


Un package peut être considéré comme une bibliothèque de classes : Il permet de
regrouper un certain nombre de classes qui sont proches dans une seule famille et ainsi
d’apporter un niveau de hiérarchisation supplémentaire au langage.

Figure 6.1 – Organisation hiérarchique de package

Mahdi Khemakhem (NAU-IIT 12/13) 56


6.2 La structure de stockage des classes et des packages

Dans cet exemple :


– La classeButton appartient au package java.awt(sous-package du package java)
– La classe ActionEvent appartient au package java.awt.event
– Le package java ne contient que des sous-packages : lang et awt
Il y a deux manières d’utiliser une classe stockée dans un package :
– En utilisant le nom du package suivi du nom de la classe

java.util.Date now = new java.util.Date() ;


System.out.println(now) ;

– En utilisant le mot clé import pour importer (inclure) le package auquel appartient
la classe

import java.util.Date ; // Ne permet d’importer que la classe Date de


java.util
...
Date now = new Date() ;
System.out.println(now) ;

iimport java.util.* ; // Permet d’importer toutes les classes de java.util


...
Date now = new Date() ;
System.out.println(now) ;

On peut généralement utiliser l’une ou l’autre de ces deux méthodes, mais il existe un
cas ou l’on doit obligatoirement utiliser la première : si deux classes portant le même nom
sont définies dans deux packages différents.
Java importe automatiquement le package java.lang qui permet d’utiliser
des classes comme Thread ou System.
Remarque : System est une classe de java.lang, out est une variable statique de cette
classe (de type PrintStream) et println est une méthode de la classe PrintStream.

6.2 La structure de stockage des classes et des packages


Les fichiers sources Java ont pour extension .java, les fichiers compilés (donc contenant
du Byte code) ont pour extension .class.

Mahdi Khemakhem (NAU-IIT 12/13) 57


6.2 La structure de stockage des classes et des packages

Seules les classes public sont accessibles d’un autre package, ou d’un autre fichier (les
autres classes ne sont pas connues en dehors de leur fichier). Il ne peut y avoir qu’une et
une seule classe public dans un fichier et cette classe doit porter le même nom que
le fichier (en respectant les minuscules / majuscules).
Les fichiers des classes qui font partie d’un package doivent être placés dans une hiérar-
chie de répertoires correspondant à la hiérarchie des packages. Ils doivent obligatoirement
commencer par une déclaration précisant le nom de leur package, précédé du mot clé
package.

// Fichier Classe1.java dans le répertoire test/util/


package test.util ;
public class Classe1
{
public void test() {. . .} }

// fichier Appli1.java dans le sous répertoire application


// la déclaration de package est inutile, puisque cette classe n’est pas destinée à être
// utilisée par d’autres
import test.util.* ;
public class Appli1
{
public static void main(String args[])
{
Classe1 c = new Classe1() ;
c.test() ;
}
}

Mahdi Khemakhem (NAU-IIT 12/13) 58


6.3 Les principaux packages du JDK

6.3 Les principaux packages du JDK


java.applet Classes de base pour les Applets
java.awt Interface Utilisateur
java.io Entrées/Sorties, fichiers . . .
java.lang Classes faisant partie du langage
java.net Accés au réseau
java.util conteneurs, dates. . .

Table 6.1 – Les principaux packages du JDK

6.4 Les règles de visibilité des attributs et des mé-


thodes
On a déjà abordé les règles de visibilité des classes (public : accès à tous, private :
accès uniquement pour les classes du même fichier).
En ce qui concerne les méthodes et les attributs, il existe 4 niveaux de visibilité qui
permettent de définir si telle méthode ou tel attribut est visible pour les classes du même
package, pour celles en dehors du package courant et pour les classes dérivées.
La visibilité friendly est celle prise par défaut.

Accessible méthode de la classes déri- classes du classes déri- classes des


aux : même classes vées dans le même package vées dans un autres pa-
même package autre package ckages
public X X X X X
protected X X X X
friendly X X X
private X

Table 6.2 – Visibilité des attributs et méthodes


Remarque :Les règles de visibilité fonctionnent au niveau des classes, pas des objets. Un
objet peut parfaitement accéder à la méthode privée d’un autre objet si celui-ci est de la
même classe.

Mahdi Khemakhem (NAU-IIT 12/13) 59


6.5 Les classes imbriquées et les classes anonymes

Pour respecter les concepts de l’approche objet, il est nécessaire de respecter les règles
de conception suivantes :
1. Les attributs doivent toujours être privés
2. Les attributs constants (final) peuvent être publics ou privés
3. Les méthodes à usage strictement interne doivent être privées
4. Si un attribut doit pouvoir être accessible de l’extérieur : définir des méthodes
publiques permettant d’y accéder.
Ces règles permettent de garantir le respect de l’encapsulation des objets.

class Personne
{ private String nom ;
public Personne(String nom) { this.nom = nom ; }
public String getNom() { return nom ; }
}. . .
Personne moi = new Personne("Toto") ;
System.out.println( moi.getNom() ) ;

6.5 Les classes imbriquées et les classes anonymes


Il est possible de définir des classes dans des classes. Il existe deux types de classes
ainsi définies :
– Les classes imbriquées : Elles possèdent un nom et sont définies au même niveau
qu’une méthode ou un attribut.
– Les classes anonymes : Elles ne possèdent pas de nom et sont définies là où elles
sont utilisées, c’est à dire dans le code.
Dans tous les cas la visibilité de ces classes est limitée aux méthodes de la classe dans
laquelle elles sont définies. Par contre elles ont accès à tous les éléments de cette classe
(même privés).
Exemple de classe imbriquée :

Mahdi Khemakhem (NAU-IIT 12/13) 60


6.5 Les classes imbriquées et les classes anonymes

public class Voiture


{ class Roue
{
private String modele ;
Roue(String modele) { this.modele = modele ; }
}
private Roue[] roues = new Roue[4] ;
private int puissance =10 ;
public Voiture(String modele_roue, int puissance)
{
this.puissance = puissance ;
for ( int i=0 ; i<roues.length ; i++ ) roues[i] = new
Roue(modele_roue) ;
}
}

Exemple de classe anonyme :

class Commande
{ public void go() { System.out.println("Pas de commande") ; }
}
class Shell
{ private Vector commandes = new Vector() ; // Objet permettant de contenir N objets
public void addCommande( Commande commande)
{commandes.addElement(commande) ;}

public void executer()


{
for ( /* Parcours de tous les éléments */ )
((Commande)e.nextElement()).go() ;
}
}

Mahdi Khemakhem (NAU-IIT 12/13) 61


6.5 Les classes imbriquées et les classes anonymes

class Principale
{ Shell shell = new Shell() ;
public static void main(String[] args)
{
shell.addCommande( new Commande()
{
public void go() { System.out.println("commande") ;}
}
);
...
shell.executer() ;
}
}

Mahdi Khemakhem (NAU-IIT 12/13) 62


Chapitre 7

Les classes de Base

Dans ce chapitre et dans les suivants, on passe en revue quelques classes indispensables
à connaître, sans trop entrer dans les détails : il est impossible et inutile de tout vouloir
apprendre sur les classes Java, il y en a trop et il sera toujours indispensable de savoir
utiliser le système d’aide et sa propre expérience pour trouver la réponse à ses questions.
Pour chaque classe on n’aborde que quelques exemples d’utilisation montrant les mé-
thodes les plus importantes à connaître.

7.1 La classe Object


La classe Object est la classe mère de toutes les classes, elle contient 2 méthodes que
la plupart des classes Java doivent redéfinir :
– String toString() : qui retourne une description de l’objet.
– boolean equals(Object) : qui permet de tester l’égalité sémantique de deux objets.
On doit aussi noter l’existence de la méthode Class getClass() qui peut être utilisée sur
tout objet pour déterminer sa nature (nom de sa classe, nom de ses ancêtres, structure).

Mahdi Khemakhem (NAU-IIT 12/13) 63


7.2 Les classes Wrapper

class Personne
{ // dérive de Object par défaut
private String nom ;
public Personne(String nom) { this.nom = nom ; }
public String toString()
{return "Classe : " + getClass().getName() + " Objet : " + nom ;}
boolean equals(Personne p) { return p.nom.equals(nom) ; }
}
Personne p1 = new Personne("Foulen Ben Foulen") ;

Personne p2 = new Personne("Foulena Ben Foulen") ;


if ( p1 == p2 ) . . .// Faux, les références sont différentes
if (p1.equals(p2)) . . .// Vrai, comparaison sémantique
System.out.println( p1 ) ;
// Affiche : Classe : Personne Objet : Foulen Ben Foulen

Remarque : Lorsqu’on affiche un objet avec la méthode println(obj), c’est la méthode


toString() de cet objet qui est utilisée pour afficher son contenu.

7.2 Les classes Wrapper


On a vu que les types de base de Java ne sont pas des objets (int, double, . . .). Les
classes Wrapper sont des classes qui permettent de représenter les types de base sous
forme d’objets :
– Boolean pour boolean
– Integer pour int
– Float pour float
– Double pour double
– Long pour long
– Character pour char
Elles permettent en particulier de :
– Récupérer les valeurs minimum et maximum du type de base correspondant.
– Un objet Wrapper peut être créé à partir d’une variable du type de base correspon-
dant ou du contenu d’une chaîne de caractères.

Mahdi Khemakhem (NAU-IIT 12/13) 64


7.2 Les classes Wrapper

– Les conversions entre types de base et chaînes de caractères sont possibles via des
objets Wrapper.
– Les objets Wrapper peuvent être contenus dans des conteneurs (au contraire des
types de base).
Attention : les objets Wrapper ne supportent pas les opérateurs classiques (+, *,. . .)
// Exemple d’accès aux valeurs min/max d’un type
double f ;
int i ;
...
if ( f > Integer.MIN_VALUE && f < Integer.MAX_VALUE) i = (int) f ;
...

// Exemple de conversion chaîne => entier (Variante 1)


int stoi(String s ) {
try { return Integer.parseInt(s) ; }
catch (Exception e) { return 0 ; }
}

// Exemple de conversion chaîne → entier (Variante 2)


int stoi(String s )
{return (new Integer(s)).intValue() ;}

// Exemple de conversion chaîne → entier (Variante 3)


int stoi(String s )
{return Integer.valueOf(s).intValue() ;}

// Exemple de conversion entier → chaîne (Variante 1)


String itos(int i )
{return (new Integer(i)).toString() ;}

// Exemple de conversion entier → chaîne (Variante 2)


String itos(int i )
{return "" + i ;}

// Exemple de conversion entier → chaîne (Variante 3)


String itos(int i )
{return String.valueOf(i) ;}

Mahdi Khemakhem (NAU-IIT 12/13) 65


7.3 Les chaînes de caractères

7.3 Les chaînes de caractères


Elles peuvent être représentées par deux classes d’objets : String et StringBuffer

7.3.1 La classe java.lang.String


Cette classe décrit des objets qui contiennent une chaîne de caractères constante
(cette chaîne ne peut pas être modifiée).
C’est une classe particulière qui est reconnue par le compilateur : une constante de
type chaîne de caractères est reconnue par celui-ci comme étant un objet de la classe
String.

String Message = "Hello World" ;

C’est aussi la seule classe qui dispose d’opérateurs supplémentaires : + et += pour la


concaténation de chaînes de caractères.
int nombre = 3 ;
String message = "Mon nombre est " + 3 ; //le nombre est converti en String
System.out.println("Mon message est : " + message ) ;
// Affiche : Mon message est : message 3

La classe String possède de nombreuses méthodes, voici quelques exemples :

Boolean chercheMot( String texte, String atrouver, boolean ignoremajuscules)


{ int ici = 0 ;
while ( ici < texte.length() )
{
int suivant = texte.indexOf( ’,’, ici ) ;
if ( suivant == -1 ) suivant = texte.length() ;
String mot = texte.substring( ici, suivant) ;
if ( ignoremajuscules ) { if ( mot.equalsIgnoreCase( atrouver ) ) return true ; }
else if ( mot.equals( atrouver ) ) return true ;
ici = next+1 ;
}
return false ;
}

Mahdi Khemakhem (NAU-IIT 12/13) 66


7.3 Les chaînes de caractères

Description rapide des méthodes utilisées :


– int length() Retourne le nombre de caractères compris dans la chaîne.
– int indexOf(char c, int i) Retourne la position du caractère c en partant de la
position i
– String substring(int i, int j) Retourne une chaîne extraite de la chaîne sur laquelle
est appliquée cette méthode, en partant de la position i à la position j
– boolean equals(String s) comparaison sémantique des chaînes.

7.3.2 La classe java.lang.StringBuffer


La classe StringBuffer permet de représenter des chaînes de caractères de taille va-
riable. Contrairement à la classe String, il n’est pas possible d’utiliser l’opérateur + avec
les objets de cette classe.
Lorsqu’un objet du type StringBuffer est construit, un tableau de caractères est
alloué dans l’objet. Sa taille initiale est de 16, mais si l’on ajoute plus de 16 caractères
dans l’objet, un nouveau tableau, plus grand est alloué (les caractères sont recopiés de
l’ancien tableau vers le nouveau et l’ancien tableau est détruit).
Un objet de la classe StringBuffer se caractérise donc par deux tailles, qui sont retour-
nées par les méthodes :
– int length() : qui retourne le nombre de caractères réellement contenus
– int capacity() : qui retourne la taille actuelle du tableau interne
Quelques méthodes supplémentaires :
– StringBuffer append(p) : ajoute p en fin de chaîne (p est n’importe quel type de
base)
– StringBuffer insert(int offset, p) : idem, mais en insérant p à l’emplacement
indiqué par offset
– StringBuffer reverse() : inversion des caractères de la chaîne.

7.3.3 La classe java.util.StringTokenizer


Cette classe permet de construire des objets qui savent découper des chaînes de carac-
tères en sous-chaînes (C’est un objet ayant un caractère utilitaire → package java.util).
Lors de la construction du StringTokenizer, il faut préciser la chaîne à découper et,
dans une seconde chaîne, le ou les caractères qui doivent être utilisés pour découper cette
chaîne.

Mahdi Khemakhem (NAU-IIT 12/13) 67


7.4 Les conteneurs

void AfficheParMots(String texte)


{
StringTokenizer st = new StringTokenizer(texte, ", :") ;
while ( st.hasMoreTokens() )
{
String mot = st.nextToken() ;
System.out.println(mot) ;
}
}
...
AfficheParMots("Lundi,Mardi :Mercredi ;Jeudi") ;
// Affiche :
Lundi
Mardi
Mercredi ;Jeudi

7.4 Les conteneurs


Les conteneurs sont des objets qui permettent de contenir d’autres objets. Le premier
conteneur qu’on a vu est le tableau, qui est un élément de base du langage Java, et qui
peut contenir des références à des objets ou des types de base.
Les conteneurs qu’on va voir dans ce chapitre permettent de contenir des réfé-
rences à des objets dérivant de la classe Object, c’est à dire tout objet appartenant
à une classe (mais pas les types de base, sauf si l’on utilise un Wrapper).
Les méthodes proposées par les conteneurs (pour accéder à leur contenu) retournent
des références de type Object que l’on devra souvent convertir explicitement vers le
type approprié.

7.4.1 La classe java.util.Vector


Les objets de la classe Vector sont aux tableaux ce que les StringBuffer sont aux
String : Ils représentent des tableaux à taille variable. Le fonctionnement interne de ces
deux classes est d’ailleurs très similaire (redimmensionnement automatique du tableau
interne si cela est nécessaire).

Mahdi Khemakhem (NAU-IIT 12/13) 68


7.4 Les conteneurs

Les objets de la classe Vector étant à taille variable, il n’y a pas de limite au nombre
d’objets qu’il peut contenir (la seule limite est la taille de la mémoire).
Exemple d’utilisation :

Vector vec = new Vector() ;


for (int i=0 ; i<10 ; i++)
{
Integer element = new Integer(i) ;
vec.addElement(element) ; // Ajout en fin de Vecteur
}
//⇒0 1 2 3 4 5 6 7 8 9
Integer i = new Integer(15) ;
vec.insertElementAt(i,5) ; // Insertion à la position indiquée
//⇒ 0 1 2 3 4 15 5 6 7 8 9
vec.removeElementAt(0) ; // Suppression de l’élément indiqué
// ⇒ 1 2 3 4 15 5 6 7 8 9
Integer j = (Integer)vec.elementAt(6) ;
// j contient une référence sur l’objet Integer contenant 5
vec.removeAllElements() ; // Suppression de tous les éléments

Autres méthodes disponibles :


– Object elementAt(int index) : retourne (sans retirer) l’élément à la position
index
– void setElementAt(Object obj) : place l’objet à la position indiquée (remplace-
ment)
– boolean contains(Object obj) : retourne true si obj est dans le tableau
– int indexOf(Object obj) : retourne la position de obj (-1 si obj n’est pas présent)
– int size() : retourne la taille du tableau

7.4.2 L’interface java.util.Enumeration


Un objet implémentant l’interface Enumeration permet de parcourir les éléments
d’un conteneur (c’est un itérateur de conteneur).
Un tel objet ne contient pas de données mais il contient une référence à un conteneur
et une "position courante" dans ce conteneur.

Mahdi Khemakhem (NAU-IIT 12/13) 69


7.4 Les conteneurs

Enumeration est l’interface unique pour le parcours de tous les types de conteneurs
définis dans les classes de base de Java. Un objet implémentant cette interface permet de
réaliser une et une seule itération sur le conteneur qui lui est associé.
Pour les conteneurs de type Vector, la méthode elements() permet de récupérer un
objet implémentant l’interface Enumeration. Il est alors possible d’utiliser deux méthodes
sur cet objet :
– boolean hasMoreElements() : Teste s’il reste des éléments à parcourir
– Object nextElement() : Retourne l’élément courant et passe au suivant

// Soit le conteneur :
Vector vec = new Vector() ;
for (int i=0 ; i<10 ; i++)
{
Integer element = new Integer(i) ;
vec.addElement(element) ;
}
//⇒ 0 1 2 3 4 5 6 7 8 9
// Exemple de parcours sans itérateur :
for (int i=0 ; i<vec.size() ; i++ )
System.out.println( vec.elementAt(i) ) ;
// Exemple de parcours avec itérateur :
for (Enumeration e = vec.elements() ; e.hasMoreElements() ; )
System.out.println(e.nextElement()) ;

7.4.3 La classe java.util.Hashtable


On suppose qu’on veuille chercher un objet dans un conteneur (par exemple l’adresse
de quelqu’un dans un carnet d’adresses) : Avec un Vector la seule méthode à utiliser
sera : je parcours mon conteneur tant que je ne trouve pas l’élément qui m’intéresse (tant
que je n’ai pas trouvé l’adresse correspondant au nom de la personne qui m’intéresse)
La classe Hashtable permet de créer des conteneurs qui savent indexer chaque objet
contenu par une clé unique : si je cherche un élément, il suffit de connaître sa clé (par
exemple le nom de la personne dont on cherche l’adresse) et la table de hashing fournira
un accès direct et performant à cet élément.

Mahdi Khemakhem (NAU-IIT 12/13) 70


7.4 Les conteneurs

Les clés peuvent être n’importe quel objet implémentant la méthode hashCode()
de la classe Object. C’est par exemple le cas des chaînes de caractères (String) ou des
Wrapper. Une certaine clé ne peut identifier qu’une seule valeur.
Les conteneurs Hashtable sont très performants pour les opérations d’accès
directs aux objets contenus.
Voici un échantillon des méthodes disponibles :
– Object put(Object cle, Object elt) : Insère l’élément elt avec la clé cle
– Object remove(Object cle) : Supprime et retourne l’objet correspondant à la clé
cle
– Object get(Object cle) : Retourne l’objet correspondant à la clé cle
– boolean containsKey(Object cle) : Teste si un objet correspondant à la clé
existe
– keys() : Retourne une Enumeration sur les clés
– elements() : Retourne une Enumeration sur les éléments

class Adresse
{
private String nom, adresse ;
public Adresse(String nom, String adresse) { this.nom = nom ; this.adresse =
adresse ; }
public String toString() { return nom + " : " + adresse ; }
}
Hashtable carnet = new Hashtable() ;
carnet.put("Foulen Ben Foulen", new Adresse("Foulen Ben Foulen", "9, Rue Sans
Nom 5000 Gabes") ) ;
carnet.put("Foulena Ben Foulen", new Adresse("Foulena Ben Foulen", "18, avenue
Grande 3000 Sfax")) ;
...
Adresse rech = (Adresse)carnet.get("Foulen Ben Foulen") ;

Remarque : La méthode get() retourne une référence du type Object⇒ On est donc
obligés de convertir explicitement la référence retournée en objet de la classe Adresse.
Dans l’exemple précédent, on peut considérer que le conteneur carnet va permettre de
contenir l’ensemble des objets de la classe Adresse. Il serait donc logique de considérer

Mahdi Khemakhem (NAU-IIT 12/13) 71


7.4 Les conteneurs

qu’il s’agit d’un attribut de cette classe et d’encapsuler ainsi la gestion des membres de
cette classe (avec des méthodes static). On reprend l’exemple :

class Adresse
{
private static Hashtable carnet = new Hashtable() ;
private String nom, adresse ;
public Adresse(String nom, String adresse)
{
this.nom = nom ; this.adresse = adresse ;
carnet.put(nom, this) ;
}
public String toString() { return nom + " : " + adresse ; }
public static Adresse get( String nom ) { return (Adresse)carnet.get(nom) ; }
public static Enumeration adresses() { return carnet.elements() ; }
}
new Adresse("Foulen Ben Foulen", "9, Rue Sans Nom 5000 Gabes") ;
new Adresse("Foulena Ben Foulen", "18, avenue Grande 3000 Sfax") ;
...
Adresse rech = Adresse.get("Foulen Ben Foulen") ;
for (Enumeration e = Adresse.adresses() ; e.hasMoreElements() ; )
System.out.println( e.nextElement() ) ;// inutile de convertir l’objet, car toString()
est une méthode de la classe Object

Mahdi Khemakhem (NAU-IIT 12/13) 72


7.4 Les conteneurs

Mahdi Khemakhem (NAU-IIT 12/13) 73

Vous aimerez peut-être aussi