Cours Java
Cours Java
Université de la Méditerranée
[email protected]
http ://www.esil.univ-mrs.fr/˜chaouiya
Chapitre 1
Introduction
1
1.2. PROGRAMMATION MODULAIRE
void fonction1(....) {
....
x=pgcd(1990,y);
....
}
Exemple de la pile
#include <stdio.h>
typedef struct elt {
char info;
struct elt *suiv;
} Maillon, *Pile;
Les types abstraits de données (TAD) sont basés sur deux idées :
– L’encapsulation : c’est la définition d’un type et d’un ensemble d’opérations
pour le manipuler à l’intérieur d’une unité syntaxique (un contenant : fichier,
classe, module, package, etc.)
– La dissimulation de l’information : c’est le masquage des détails d’implémentation
qui ne concernent pas l’utilisateur de l’abstraction.
L’encapsulation est utilisée pour la compilation séparée : on regroupe dans un
fichier les parties d’un programme qui sont sémantiquement liées. Lors d’une modi-
fication, on n’a pas à recompiler tout le programme mais seulement le module qui a
changé. Les TAD sont définis par :
– La spécification du type tel que vu de l’extérieur, elle définit comment utiliser
le type (données et opérations accessibles). Elle décrit aussi l’interface, ce qui est
exporté. Les programmes utilisant le TAD importent l’interface pour pouvoir
utiliser le type.
– La représentation des objets de ce type (structure de donnée du type), elle
décrit comment les objets du TAD sont construits.
– L’implémentation des opérations qui manipulent les objets de ce type. Il y a
parfois deux opérations particulières : constructeur et destructeur qui spécifient
comment créer un objet du type et quoi faire quand on veut le détruire.
Un bon TAD ne devrait exporter que des opérations, pas de données (champs).
Eventuellement, les données sont accédées au travers d’opérations très simples ap-
pelées fonctions d’accès (getters et setters) pour donner une valeur ou extraire la
valeur d’une donnée.
L’héritage Une notion fondamentale en POO est la notion d’héritage. Si l’on re-
prend notre exemple des formes géométriques, une façon de procéder est de définir la
classe FormeGeometrique avec les attributs et comportements communs à toutes les
formes géométriques. La sous-classe Cercle hérite alors de la classe FormeGeometrique
et a ses propres spécificités.
FormeGeometrique
type (chaine de caracteres)
centre (point)
couleur (de remplissage)
afficher()
HH
H
HH
H
HH
H
j
Carre Rectangle
longueur ? longueur
Cercle largeur
rayon
1.4.6 Distribué
Syntaxe de base
2.1.2 Commentaires
Java reconnait trois types de commentaires :
– les commentaires sur une ligne : tous les caractères suivants //... jusqu’à la
fin de la ligne sont ignorés
– les commentaires multilignes : tous les caractères entre /* ... et...*/ sont
ignorés
– les commentaires de documentation : quand ils sont placés juste avant une
déclaration, les caractères entre /** ...et...*/ sont inclus dans une docu-
mentation générée automatiquement par l’utilitaire javadoc.
2.1.3 Identificateurs
Les identificateurs ne peuvent commencer que par une lettre, un souligné (’ ’) ou
un dollar (’$’). Les caractères suivants peuvent être des lettres ou des chiffres ou tout
caractère du jeu Unicode de code supérieur à H00C0.
9
2.1. UNITÉS LEXICALES
Note : on convient de réserver des noms commençant par une majuscule aux classes,
les noms composés sont sous la forme “NomComposé” ou bien “nomComposé”, et de
façon générale, on conseille de nommer les variables et méthodes de façon parlante.
* indique un mot clé qui n’est pas utilisé dans les versions actuelles
Il y a encore trois mots réservés du langage qui ne sont pas des mots clés mais
des littéraux :true false et null.
Caractères
Le type caractère est char. Il est représenté sur 16 bits (jeu de caractères Uni-
code).
Booléens
Le type booléen est boolean. Les deux seules valeurs qu’il peut prendre sont true
et false. Il s’agit du type retourné par les opérateurs relationnels (cf.2.3.4).
Entiers
Ils sont très similaires à ceux de C, sinon qu’ils sont indépendants de la plate-
forme. Les 4 types d’entiers sont :
– byte =⇒ entier sur 8 bits (complément à 2)
– short =⇒ entier sur 16 bits (complément à 2)
– int =⇒ entier sur 32 bits (complément à 2)
– long =⇒ entier sur 64 bits (complément à 2)
Réels
Il n’y a que deux types de réels en Java :
– float=⇒ représenté sur 32 bits
– double=⇒ représenté sur 64 bits
Constantes caractères
Elles sont constituées d’un caractère ou une séquence d’échappement entre des
guillemets simples :
’a’, ’b’,...
’\’’, ’\"’, ’\\’
’\n’ nouvelle ligne
’\t’ tabulation
Constantes entières
Elles peuvent s’écrire
– en notation décimale : 123, -123
– en notation octale avec un zéro en première position : 0123
Constantes réelles
Elles se présentent sous la forme d’une partie entière suivie d’un point (.), suivi
d’une partie décimale, d’un exposant et un suffixe de type. L’exposant est un E ou e
suivi d’un entier.
3.1415, 3.1E12, .1E-4
2.0d (ou 2.0D) est un réel double
2.0f (ou 2.0F) est un réel float
...
for(int i=0;i<10;i++) {
...
// i est visible dans ce bloc
}
...
2.3.4 Opérateurs
Le tableau 2.2 présente tous les opérateurs du langage, avec leur ordre d’évaluation
et leur sémantique. Il manque dans ce tableau les opérateurs :
– les opérateurs d’affectation (+=, -=, *=, ...) dont l’évaluation est faite de droite
à gauche,
– les opérateurs de manipulation de bits :
& (ET bit à bit), | (OU bit à bit), ∧ (OU exclusif bit à bit) et ∼ (complémentation
bit à bit),
Exemple :
{ int i;
i=4;
System.out.println("coucou ! ");
System.out.println("i vaut "+i);
}
1
la valeur d’une expression de post-incrément est la valeur de l’opérande et a pour effet de bord
le stockage de la valeur de l’opérande incrémentée de 1, la valeur d’une expression de pré-incrément
est la valeur de l’opérande incrémentée de 1 et a pour effet de bord le stockage de cette valeur.
C’est similaire pour le décrément.
L’objet de cette section est de passer brièvement en revue toutes les structures
de contrôle (vous les connaissez déjà).
if (expression) instruction1
if (expression) instruction1 else instruction2
switch (expression) {
case cste1 :
instruction1
case cste2 :
instruction2
...
case csteN :
instructionN
default :
instructionDefaut
}
Exemple :
char c;
...
switch (c) {
case ’1’:
case ’2’:
case ’3’: // notez l’absence d’intruction
case ’5’:
case ’7’:
System.out.println(c+"est un nombre premier\n");
break; // notez l’instruction break
case ’6’:
System.out.println(c+"est un multiple de 3\n");
// notez l’absecnce de break
case ’4’:
case ’8’:
System.out.println(c+"est un multiple de 2\n");
break;
case ’9’:
System.out.println(c+"est un multiple de 3\n");
break;
default :
System.out.println(c+"n\’est pas un chiffre non nul\n");
}
...
while (condition)
instruction
Exemple :
int i=10;
while (i>=0) {
System.out.println(i);
i=i-1;
}
do
instruction
while (condition)
Exemple :
int i=-1;
do {
System.out.println(i);
i=i-1;
} while (i>=0);
Enfin, l’instruction for qui comporte une initialisation, une condition d’arrêt, et
une ou des instructions de fin de boucle :
est équivalente à :
instruction1;
while (condition_de_poursuite) {
instruction3
instruction2
}
La virgule (,) est utilisée pour combiner plusieurs initialisations et plusieurs ins-
tructions de fin de boucle.
label : instruction
L’instruction break déjà vue avec le switch est utilisée aussi dans les structures
de boucle et permet la sortie immédiate de la boucle, sans tenir compte des conditions
d’arrêt de cette dernière. Une variante permet d’associer une étiquette à l’instruction
break.
label : instruction1
while(...){
...
break label;
...
}
Ceci dit, l’usage des étiquettes et du break est fortement déconseillé, ce n’est
pas élégant, cela nuit à la lisibilité du programme, c’est contraire aux principes de la
programmation structurée ! La plupart du temps, on peut s’en passer.
L’instruction continue apparaı̂t dans les structures de boucles. Elle produit
l’abandon de l’itération courante et, si la condition d’arrêt n’est pas satisfaite, le
démarrage de l’itération suivante.
L’instruction return quant à elle est indispensable ! Elle provoque l’abandon de
la fonction en cours et le retour à la fonction appelante. Quand elle est suivie d’une
expression, le résultat de cette expression est la valeur que la fonction appelée renvoie
à la fonction appelante. Mais attention, il est déconseillé de placer une instruction
return dans le corps d’une boucle, cela signifie que vous n’avez probablement pas
bien écrit la condition de sortie de la boucle !
Exemple :
// Fichier Bonjour.java
public class Bonjour {
public static void main(String[] arg) {
System.out.println("Bonjour !\n");
}
}
On a défini une classe Bonjour qui ne possède qu’une seule méthode. La méthode
main doit être déclarée static et public pour pouvoir être invoquée par l’in-
terpréteur Java. L’argument arg est un tableau de chaı̂nes de caractères qui corres-
pond aux arguments de la ligne de commande lors du lancement du programme.
Avant tout, il faut compiler ce programme avec la commande javac :
javac Bonjour.java
La compilation traduit le code source en byte code. Le compilateur produit autant
de fichiers que de classes présentes dans le fichier source. Les fichiers compilés ont
l’extension .class.
java Bonjour
Classes et Objets
En C on utilise des structures pour crér des TAD (Types Abstraits de Données),
ou structures de données complexes. Dans les langages orientés objets, on utilise le
concept de classes. Elle permettent de définir de nouveaux types de données qui se
comportent comme des types prédéfinis et dont les détails d’implémentation sont
cachés aux utilisateurs de ces classes. Seule l’interface fournie par le concepteur peut
être utilisée.
Un objet est une instance d’une classe (qui peut être vue comme un moule). Les
objets communiquent entre eux par des messages qui sont évalués par des méthodes.
Ces messages évalués par des méthodes de l’objet, induisent des modification de son
état ou de son comportement. Les objets vivent en famille, et peuvent donc hériter
des caractéristiques de leurs ancêtres, en affinant (spécialisant) ces caractéristiques.
Un objet est caractériqé par :
– un ensemble d’attributs, typés et nommés représentant des propriétés statiques.
L’ensemble des valeurs des attributs consitue l’état de l’objet,
– un ensemble de méthodes, définissant son comportement et ses réactions à
des stimulations externes. Ces méthodes implémentent les algorithmes que l’on
peut invoquer sur ces objets,
En Java, on ne peut accéder à un objet que par une référence vers celui-ci. Une
référence est une sorte de pointeur vers la structure de données, avec la différence qu’il
est interdit de manipuler les références comme les pointeurs en C ou C++. On ne peut
pas connaı̂tre la valeur d’une référence, ni effectuer d’opérations arithmétiques. La
seule manipulation possible consiste à changer la valeur de la référence pour qu’elle
“fasse référence” à un autre objet.
Une classe est un moule d’objets, elle en décrit la partie privée (structure de
données interne ou attributs et corps des méthodes), et la partie publique (nom
et paramètres des méthodes). C’est un générateur d’objets, on peut ainsi créer un
ensemble d’objets rentrant dans ce moule.
21
3.1. DÉCLARATION DES CLASSES
– les structures de données associées aux objet de la classe, les variables désignant
ces données sont appelées champs ou attributs,
– les services ou comportements associés aux objets de la classe qui sont les
méthodes, définies dans la classe.
3.1.2 Méthodes
Elles sont définies par un identificateur, des paramètres formels, un type de retour,
un corps et éventuellement un qualificatif (comme pour les champs) public, private
ou protected.
class Date{
private int mois;
private int jour;
private int annee;
...
public void affecter(int m, int j, int a) {
mois=m; jour=j; annee=a;
}
public int quelJour(){return jour;}
public int quelMois(){return mois;}
public int quelleAnnee(){return annee;}
public void imprimer(){
System.out.println(jour+"/"+mois+"/"+annee);
}
}
La méthode affecter fait partie de la classe Date, il lui est donc permis d’accéder
à ses champs privés. Et cette méthode, puisqu’elle est déclarée public, permet de
modifier les champs d’un objet de la classe Date. Les méthodes publiques d’une classe
constituent ce que l’on appelle son interface publique.
Contrairement au langage C++ la définition effective des méthodes de la classe
doit se faire dans la définition de la classe.
Une méthode est un message envoyé à un objet. Ainsi, pour afficher la date
contenue dans l’objet d, on lui envoie le message imprimer :
d.imprimer();
De telles méthodes sont appelées méthodes d’instances, elles sont évoquées via un ob-
jet. Nous verrons plus loin qu’il existe des méthodes de classes. La méthode imprimer
n’est utilisable que parce qu’elle fait partie des méthodes publiques. Par contre, il ne
sera pas possible d’accéder aux champs d.jour, d.mois et d.annee car ce sont des
données privées.
Date d;
La variable d représente une référence vers un objet de type Date qui doit être
instancié (créé) explicitement avec le mot clé new et le constructeur (cf. section3.1.4)
de la classe Date :
3.1.4 Constructeurs
On a dit que pour définir un objet d’une classe, il fallait faire appel à son construc-
teur. En l’absence de constructeur(s) explicite(s), un constructeur implicite, sans
argument, est invoqué par défaut.
Lorsque l’on veut définir un objet, il est souvent utile de pouvoir initialiser cet
objet. Dans notre exemple de la classe Date, il est possible d’utiliser la méthode
affecter pour donner une valeur aux champs d.jour, d.mois et d.annee.
Mais ce n’est pas très agréable. Le constructeur est une méthode spécifique qui est
automatiquement appelée lors de la création d’un objet. Elle a la particularité de
porter le même nom que la classe, d’être publique et n’a pas de valeur de retour.
class Date {
...
public Date(int j, int m, int a) {
jour=j; mois=m; annee=a;}
...
}
Maintenant, pour créer un objet de type Date il faudra fournir impérativement
le jour, le mois et l’année. On peut contourner ce problème en fournissant plusieurs
constructeurs :
class Date {
...
public Date(int j, int m, int a) {
jour=j; mois=m; annee=a;}
public Date(int j, int m) {
jour=j; mois=m; annee=2000;}
public Date(int j) {
jour=j; mois=1; annee=2000;}
public Date() {
jour=1; mois=1; annee=2000;}
...
}
3.1.5 Destructeurs
En général, en Java, on n’a pas à se soucier de la restitution de l’espace mémoire
occupé par un objet qui n’est plus référencé. On a déjà évoqué le “ramasse-miettes”
(garbage collector) qui est un système de récupération de mémoire automatique. Par
défaut, ce système tourne en arrière-plan pendant l’exécution de vos programmes. Il
repère les objets qui ne sont plus référencés, et libère l’espace en mémoire alloué à
ceux-ci. Vous pouvez désactiver le ramasse-miettes (option -noasyngc sur la ligne
de commande de lancement de la JVM).
Selon les applications, un objet peut bloquer d’autres types de ressources que la
mémoire (descripteur de fichiers, socket, ...), il est alors bon d’utiliser un destruc-
teur pour libérer ces ressources. De plus, vous pouvez ne pas vouloir attendre que
le ramasse-miettes libère des ressources critiques. Il existe une méthode spécifique
finalize qui est un destructeur et redéfinit la méthode protected void finalize
de la classe Object. Une classe peut donc implémenter une méthode finalize qui
est déclarée de la façon suivante :
protected void finalize() throws Throwable {
super.finalize();
...
}
Ce code s’éclaircira plus tard, avec les notions d’héritage et d’exceptions.
Exemple :
class Date{
private int mois;
private int jour;
private int annee;
public static int nbDate=0;
class Programme{
public static void main(String[] arg){
Date aujourdhui=new Date(25,9,2000);
Date noel=new Date(25,12,2000);
aujourdhui.imprimer();
noel.imprimer();
System.out.println(noel.nbDate);
System.out.println(Date.nbDate);
}
}
25/9/2000
25/12/2000
2
2
Dans l’exemple qui suit, l’intérêt du mot clé this est certainement mieux illustré.
On crée une liste chaı̂née de tous les objets de type Date qui ont été instanciés :
class Date{
On appelle signature d’une méthode, la donnée de son nom, du nombre de ses pa-
ramètres formels et de leurs types.
class Date{
private int mois;
private int jour;
private int annee;
private Date suivant;
public static Date listeDates=null;
public Date(int j, int m, int a){
jour=j; mois=m; annee=a;
suivant=listeDates;
listeDates=this;
}
...
public void imprimer(){
System.out.println(jour+"/"+mois+"/"+annee);
}
public static void listerDate(){
Héritage
4.1 Introduction
La notion d’héritage est fondamentale en POO. Elle permet de spécialiser des
classes. Reprenons l’exemple de la classe Date, et supposons que nous devions main-
tenant définir une classe DateAnniversaire, qui associe à une date donnée le nom
et le prénom d’une personne née à cette date. Une première solution consisterait à
définir complètement la nouvelle classe :
class DateAnniversaire{
private int mois;
private int jour;
private int annee;
private String nom;
private String prenom;
public DateAnniversaire(int j,int m,int a,String n,String p) {
jour=j; mois=m; annee=a;
nom=n; prenom=p;
}
public affecter(int m,int j,int a,String n,String p) {
jour=j; mois=m; annee=a;
nom=n; prenom=p;
}
...
public void imprimer(){
System.out.println(prenom+" "+nom+" est ne le "+jour+"/"+mois+"/"+annee);
}
}
30
4.1. INTRODUCTION
sous classe doit évidemment compléter (enrichir) la classe de base, on parle aussi de
spécialisation. Elle définit donc des champs et comportements supplémentaires, et
peut, éventuellement, modifier une ou des méthodes de la classe de base.
Notre exemple de classe DateAnniversaire possède beaucoup de caractéristiques
de la classe Date (évidemment, c’est une date !). Elle comporte deux champs supplé-
mentaires, et les méthodes (constructeur, méthodes d’accès et de modification) doivent
être complétées et/ou adaptées en fonction de l’ajout de ces nouveaux champs. On
définira la classe DateAnniversaire comme une sous classe de la classe Date. Cela
se fait en Java grâce au mot clé extends.
Voici l’exemple complet de la classe DateAnniversaire. Nous y reviendrons par
la suite :
class Date {
protected int mois;
protected int jour;
protected int annee;
public Date(int j, int m, int a) {
jour=j; mois=m; annee=a;
}
public void affecter(int j, int m, int a) {
mois=m; jour=j; annee=a;
}
class TestDate{
public static void main(String[] arg){
DateAnniversaire d=new DateAnniversaire(0,0,0,"","");
d.affecter(10,3,1920,"Boris","Vian");
d.imprimer();
}
}
Maintenant, vous devez mieux comprendre les qualificatifs donnés aux champs
de la classe Date.
Ainsi le constructeur de la classe dérivée devra faire appel à celui de la classe de base
pour l’initialisation de ces champs. Dans notre exemple de dates, on dira que pour
créer une DateAnniversaire, il faut d’abord créer une Date.
Voici quelques points essentiels :
– Le constructeur est appelé au moment de la création de l’objet (instanciation).
Il initialise cet objet en fonction des paramètres fournis.
– Si la classe ne comporte pas de constructeur, Java en crée un de façon implicite,
sans paramètre. Mais attention, si la classe a au moins un constructeur avec
paramètre(s) et aucun sans paramètre, elle n’a alors plus de constructeur par
défaut.
– Si, la première instruction du constructeur n’est pas un appel explicite d’un
constructeur de la classe de base (utilisation de super(...), voir plus loin), le
constructeur par défaut de la classe de base est appelé.
– Si la classe de base n’a pas de constructeur par défaut (ou de constructeur sans
paramètre), on a une erreur de compilation (j’ai repris l’exemple des dates, et
enlevé l’appel explicite au constructeur de la classe Date dans celui de la classe
DateAnniversaire) :
Date2.java:20: No constructor matching Date2() found in class Date2
public DateAnniversaire(int j,int m,int a,String n,String p) {
^
1 error
...
public void uneMethode(){
i=0; // champ defini dans la classe B
this.i=0; // champ defini dans B
super.i=1; // champ defini dans A
((A) this).i=1; // champ defini dans A
...
}
}
class C extends B {
public int i;
...
public void uneMethode(){
i=0; // champ defini dans la classe C
this.i=0; // champ defini dans C
super.i=1; // champ defini dans B
((B) this).i=1; // champ defini dans B
((A) this).i=1; // champ defini dans A
...
}
}
class Fruit{
public String nom;
public Fruit(String n) {
nom=n;
}
public void imprimer() {
System.out.println("je suis un(e) "+nom);
}
public String getNom(){
return nom;
}
}
class Pomme extends Fruit{
public Pomme(){
super("pomme");
}
public void imprimer() {
System.out.println("je suis une "+nom);
}
}
class Test{
public static void main(String[] arg){
Fruit f=new Fruit("ananas");
Pomme p=new Pomme();
f.imprimer();
System.out.println(f.getNom());
p.imprimer();
f=(Fruit)p;
f.imprimer();
System.out.println(p.getNom());
System.out.println(f.getNom());
}
}
/*** exemple d’execution :
je suis un(e) ananas
ananas
je suis une pomme
je suis une pomme
pomme
pomme
*/
Date d;
DateAnniversaire da;
...
da=d; // erreur compilation !
d=da; // OK
da=(DateAnniversaire) d // OK
4.8 Interfaces
Java ne permet pas l’héritage multiple. Il pallie ce manque par l’introduction des
interfaces. Les interfaces peuvent être vues comme des modèles, sortes de classes
ne possédant que des champs static final (c’est-à-dire des constantes) et des
méthodes abstraites. On pourrait dire que les interfaces sont des classes abstraites
dont toutes les méthodes sont abstraites et publiques et tous les champs sont publics
et constants.
Qualificatifs pour une interface : Une interface peut être qualifiée de public,
auquel cas elle sera utilisable par n’importe quelle classe. En l’absence de ce qualifi-
catif, elle ne peut être utilisée que par les classes du même paquetage. Contrairement
aux classes, on ne peut qualifier une interface de private ni protected.
Dériver une interface : Comme pour les classes, on peut organiser les interfaces
de façon hiérarchique.Mais contrairement aux classes, une interface peut dériver plu-
sieurs autres interfaces.
interface Service {
...
}
class X implements Service {
...
}
Par l’utilisation du mot clé implements, la classe promet d’implémenter toutes les
méthodes déclarées dans l’interface. La signature d’une méthode implémentée doit
évidemment être identique à celle qui apparait dans l’interface, sinon la méthode est
considérée comme une méthode de la classe et non de l’interface.
39
Chapitre 6
6.1 Tableaux
Ce sont des suites d’objets de même type. Le nombre d’éléments est fixe et est
appelé taille du tableau. Les tableaux sont des objets et leurs éléments sont soit de
type primitif, soit des références. Pour utiliser un objet de type tableau, il faut donc
définir une variable de type référence :
int [] tab1;
int tab2[];
Ces variables sont des références ; l’espace mémoire nécessaire pour coder la suite des
objets est réservé avec le mot clé new et l’opérateur [] :
40
6.1. TABLEAUX
6.1.4 Initialisation
Lors de la création d’un tableau, ses éléments sont initialisés à une valeur par
défaut. Pour les tableaux de nombres (entiers et flottants), la valeur initiale est zéro,
pour les tableaux de références, la valeur initiale est null.
Attention ! Définir un tableau d’objets ne définit qu’un tableau de références. Les
objets devront être alloués ultérieurement.
Comme pour les tableaux à une dimension, on peut initialiser les tableaux multidi-
mensions au moment de leur définition :
int[][]mat = {{1,0,0,{0,1,0},{0,0,1}};
int [][]pascal ={{1},{1,1},{1,2,1},{1,3,3,1}{1,4,6,4,1}};
Notez que dans le cas du tableau pascal, les sous-tableaux sont tous de taille
différente. Les noms de ces sous-tableaux sont pascal[0], pascal[1], .... On
doit toujours spécifier la première dimension quand on crée le tableau, on peut ne
spécifier les dimensions suivantes qu’au moment de la création des sous-tableaux.
Prototype Rôle
public String() constructeur
public String(String str) constructeur
public int length() longueur de la chaı̂ne
public char charAt(int index) caractère à la position index
public String substring(int dbt,int fin) extrait la chaı̂ne entre les positions dbt et fin
public boolean equals(Object o) test d’égalité
public boolean startsWith(String pref) test si le début de la chaı̂ne est égal à pref
public boolean endsWith(String suf) test si la fin de la chaı̂ne est égal à suf
public int compareTo(String str) comparaison des 2 chaı̂nes,(0 si str est égale,
négatif si elle est inférieure, positif sinon)
public int indexOf(int ch) position du caractère ch
public int lastIndexOf(int ch) dernière position du caractère ch
public int indexOf(int ch, int i) position de ch à partir de i
public int indexOf(String str) position de la ss-chaı̂ne str
public String replace(char c,char d) remplace toute occurrence de c par d
public String toLowerCase() conversion en minuscules
public String toUpperCase() conversion en majuscules
public char[] toCharArray() conversion en tableau de caractères
public String trim() suppression des espace en début et fin
public static String valueOf(char t[]) conversion d’un tableau de caractères en String
Exemple :
class chaines{
public static void main(String [] arg){
String a="Coucou";
String b=new String(", c’est moi !\n");
String c=a+b;
System.out.println(c);
System.out.println("longueur de a : "+a.length()); //6
System.out.println("caractere en position 2 : "+a.charAt(2)); //u
System.out.println("a est Coucou : "+a.equals("Coucou")); //true
System.out.println("a est b : "+a.equals(b)); //false
System.out.println("position de o dans a? "+a.indexOf(’o’)); //1
System.out.println("position du dernier o dans a? "+a.lastIndexOf(’o’)); //4
System.out.println("position de \"cou\" dans a? "+a.indexOf("cou")); //3
System.out.println("position de \"moi\" dans a? "+a.indexOf("moi")); //-1
System.out.println("a en majuscules : "+a.toUpperCase()); //COUCOU
System.out.println("a en minuscules : "+a.toLowerCase()); //coucou
System.out.println("a > b ? "+a.compareTo(b)); //23
Exemple :
class ReverseString{
public static String reverseIt(String source) {
int i, len=source.length();
StringBuffer dest=new StringBuffer(len);
for (i=(len-1);i>=0;i--) {
dest.append(source.charAt(i));
}
return dest.toString();
}
}
1
tiré du tutorial Java Sun
Prototype Rôle
public int length() longueur de la chaı̂ne
public char charAt(int index) caractère à la position index
public void getChars(int dbt, int fin, recopie la ss-chaı̂ne entre les positions dbt et fin,
char dst[],int index) dans le tableau dst, à partir de l’indice index
public int capacity() capacité courante
public void setCharAt(int index, char c) met le caractère c à l’indice index
public StringBuffer append(Object obj) concatène la représentation textuelle de l’obj. obj
Exceptions
7.1 Introduction
Dans un programme, il faut soigner la gestion des erreurs. Ce n’est pas toujours
facile avec les langages classiques. Java propose une approche très différente des
approches traditionnelles, à travers le mécanisme des exceptions. Une exception est
une sorte de signal indiquant qu’une erreur ou une situation anormale a eu lieu. On
dit qu’une méthode ayant détecté une situation anormale déclenche (throws) une
exception. Cette exception pourra être capturée (catch) par le code.
On peut distinguer deux types de situations anormales : les exceptions et les
erreurs. Les erreurs sont en principe des erreurs fatales et le programme s’arrête à
la suite de ce type de situation (classe java.lang.Error). Les exceptions ne sont
pas uniquement des erreurs système. Le programmeur peut définir des erreurs (non
fatales) pour assurer que son programme est robuste (classe java.lang.Exception).
Par exemple, le débordement d’un tableau est une exception.
Lorsqu’une méthode déclenche une exception la JVM remonte la suite des invo-
cations des méthodes jusqu’à atteindre une méthode qui capture cette exception. Si
une telle méthode n’est pas rencontrée, l’exécution est arrêtée.
L’uilisation des exceptions permet de :
– séparer le code correspondant au fonctionnement normal d’un programme, du
code concernant la gestion des erreurs,
– propager de proche en proche les exceptions d’une méthode à la méthode appe-
lante jusqu’à atteindre une méthode capable de gérer l’exception. Il n’est donc
pas nécessaire que la gestion d’une exception figure dans la méthode qui est
susceptible de déclencher cette exception. Une méthode peut ignorer la ges-
tion d’une exception à condition qu’elle transmette l’exception à la méthode
appelante,
– regrouper par types la gestion des exceptions.
46
7.2. QU’EST-CE QU’UNE EXCEPTION
– si instr ne se trouve pas dans un bloc try comme décrit précédemment, alors
la méthode uneMethode est terminéee. Si uneMethode est la méthode main, le
programme se termine, et l’exception n’a pas été capturée. Sinon, on se retrouve
dans une méthode qui a appelé la méthode uneMethode via une instruction
instr2 qui lance à son tour l’exception.
Une méthode susceptible de lancer une exception sans la capturer doit l’indiquer
dans son entête avec la clause throws. Cependant, comme précisé précédemment,
on est dispensé de déclarer le lancement des erreurs les plus courantes, comme par
exemple :
– ArrayOutOfBoundsException,
– ArrayStoreException,
– ArithmeticException,
– NullPointerException,
– NumberFormatException...
Exemple :1
class AttrapExcep{
static int moyenne(String[] liste) {
int somme=0, entier, nbNotes=0;
for (int i=0;i<liste.length;i++) {
try{
entier=Integer.parseInt(liste[i]);
somme+=entier;
nbNotes++;
}
catch(NumberFormatException e) {
System.out.println("La "+(i+1)+"ième note pas entière");
}
}
return somme/nbNotes;
}
public static void main(String [] arg) {
System.out.println("La moyenne est :"+moyenne(arg));
}
}
class ExceptionThrow {
static int moyenne(String[] liste) throws ExceptionRien {
int somme=0,entier, nbNotes=0;
int i;
for (i=0;i < liste.length;i++) {
try{
entier=Integer.parseInt(liste[i]);
somme+=entier;
nbNotes++;
}
catch (NumberFormatException e){
System.out.println("La "+(i+1)+" eme note n’est "+
2
http ://www.infres.enst.fr/ charon/coursJava
"pas entiere");
}
}
if (nbNotes==0) throw new ExceptionRien();
return somme/nbNotes;
}
public static void main(String[] argv) {
try {
System.out.println("La moyenne est "+moyenne(argv));
}
catch (ExceptionRien e) {
System.out.println(e);
}
}
try {
methodeBasse();
System.out.println("et ici ?");
}
finally {
System.out.println("moyenne hauteur : ou bien etre la");
}
}
static void methodeHaute() {
try {
methodeMoyenne();
}
catch(MonException e) {
System.out.println("attrape...");
}
}
static public void main(String[] argv) {
methodeHaute();
}
}
Dans ce chapitre, nous allons détailler une application qui utilise des classes
décrivant différents types de véhicules.
52
8.3. UNE CLASSE ABSTRAITE :VEHICULEAROUES
break;
case 3 : //nord
directionCourante=Ouest;
break;
case 4 : //ouest
directionCourante=Sud;
break;
}
}
public void faireDemiTour(){
switch (directionCourante.valeur) {
case 1 : //sud
directionCourante=Nord;
break;
case 2 ://est
directionCourante=Ouest;
break;
case 3 ://nord
directionCourante=Sud;
break;
case 4://ouest
directionCourante=Est;
break;
}
}
else vitesseCourante=v;
etat=e;
if (!etat) vitesseCourante=0;
couleur=c;
directionCourante=Sud;
}
public void accelerer(int param) throws VitesseExcessive{
int nouvelleVitesse = vitesseCourante+param;
if (nouvelleVitesse <0 ) vitesseCourante=0;
else if (nouvelleVitesse >vitesseMax) throw
new VitesseExcessive(this.vitesseMax);
else vitesseCourante=nouvelleVitesse;
}
public void afficher() {
if (etat)
System.out.println("Camion "+couleur +" en état de marche, roulant
à "+vitesseCourante+"km/h, sur "+nbRoues+" roues,
plein "+directionCourante.nom);
else
System.out.println("Camion "+couleur +" en panne");
}
}
}
}
taVoiture.afficher();
taVoiture.faireDemiTour();
monCamion.accelerer(-10);
monCamion.afficher();
monCamion.changerEtat();
monCamion.afficher();
}
}
Paquetage java.lang
9.1 Enveloppes
9.1.1 Classe java.lang.Number
C’est une classe abstraite mère des classes Byte, Short, Integer, Long, Float,
Double.
public abstract class Number
public Number() // constructeur
public abstract int intValue()
public abstract long longValue()
public abstract float floatValue()
public abstract double doubleValue()
public short shortValue()
59
9.1. ENVELOPPES
Nom Descriptif
Interfaces :
Clonable indique qu’un objet peut être cloné
Runnable cf chapitre sur les processus légers
Classes :
Boolean cf. ce chapitre
Byte pour le type primitif byte
Character cf. ce chapitre
Class les classes et interfaces d’une application Java
ClassLoader
Compiler
Double pour le type primitif double
Float pour le type primitif float
Integer cf ce chapitre
Long pour le type primitif float
Math cf ce chapitre
Number cf ce chapitre
Object mère de toutes les classes !
Process
Runtime
SecurityManager
hline Short pour le type primitif short
String cf chapitre 6
StringBuffer cf chapitre 6
System voir chapitre 11
Thread voir chapitre sur les processus légers
ThreadGroup
Throwable cf chapitre 7
Void pour le type primitif void
Liste des exceptions : ArithmeticException,ArrayIndexOutOfBoundsException
ArrayStoreException, ClassCastException
ClassNotFoundException, CloneNotSupportedException
Exception, IllegalAccessException
IllegalArgumentException, IllegalMonitorStateException
IllegalStateException, IllegalThreadStateException
IndexOutOfBoundsException, InstantiationException
InterruptedException, NegativeArraySizeException
NoSuchFieldException, NoSuchMethodException
NullPointerException, NumberFormatException
RuntimeException, SecurityException
StringIndexOutOfBoundsException
Le paquetage java.util
Le paquetage java.util contient des classes utilitaires telles que Vector, Stack (pour
stocker un nombre variable d’objets), Dictionnary et HashTable (pour associer deux
objets, clé/valeur), StringTokenizer (pour découper des chaı̂nes de caractères), et bien
d’autres... que je vous liste ci-dessous avec un bref descriptif (pour certains seulement !).
Pour plus d”information, n’hésitez pas à consulter la documentation de l’API ! Nous ne
détaillerons ici que les classes Vector et Stack. La classe StringTokenizer, utile pour
l’analyse de chaı̂ne de caractères, sera décrite dans le chapitre sur les entrées sorties.
Constructeurs
– public Vector()
– public Vector(int capaciteInitiale), il est conseillé d’indiquer une taille ini-
tiale
– public Vector(int capaciteInitiale,int incrementCapacite), par défaut, le
vecteur double sa taille à chaque dépassement.
63
10.1. CLASSE JAVA.UTIL.VECTOR
2. entre 2 élélements :
public final synchronized void insertElement(Object nvElt,int indice)
throws ArrayIndexOutOfBoundsException ;
Nom Descriptif
Interfaces
Enumeration génère une série d’éléments, l’un après l’autre (cf.plus loin)
EventListener cf. chapitre java.awt
Observer pour être informer du changement d’objets Observable
Classes
BitSet vecteurs redimensionnables de bits
Calendar
Date
Dictionary (abstraite) pour des tableaux associatifs
EventObject
GregorianCalendar
Hashtable (hérite de Dictionary) pour des tables de hachage
ListResourceBundle
Locale
Observable objets observables par des Observer
Properties
PropertyResourceBundle
Random pour générer un flot de nombres pseudo-aléatoires
ResourceBundle
SimpleTimeZone
Stack pile décrite plus loin
StringTokenizer p/la décomposition de chaı̂nes de caractères en unités lexicales
TimeZone
Vector vecteurs redimensionnables, décrite ci-après
Exceptions
EmptyStackException
MissingResourceException
NoSuchElementException
TooManyListenersException
2. premier élément :
public final synchronized Object firstElement()
throws NoSuchElementException ;
3. dernier élément :
public final synchronized Object LastElement()
throws NoSuchElementException ;
Changer la taille Si la nouvelle taille est supérieure à la taille courante, le vecteur est
complété par null, sinon, le vecteur est tronqué :
public final synchronized void setSize(int taille) ;
Obtenir une liste des éléments La méthode elements() renvoie un objet de type
Enumeration qui permet d’accéder aux élément de manière séquentielle (mais dans un
ordre à priori indéterminé). C’est l’interface Enumeration du paquetage java.util qui
permet d’énumérer une liste d’objets (qui peuvent être hétérogènes). Cette interfaces a
deux méthodes :
1. pour savoir s’il reste des élémentsà énumérer,
public abstract booleman hasMoreElements()
2. pour obtenir le prochain objet et avancer d’un cran,
public abstract Object nextElement()
throws NoSuchElementException
Exemple :
Enumeration e = monVecteur.elements() ;
while (e.hasMoreElements())
Object objSuivant = e.nextElement() ;
// faire ce qu’il y a lieu de faire sur objSuivant
Note : attention, objSuivant est de type Object. Il est souvent nécessaire de faire un cast
quand le vecteur contient des objets de classe spécifique.
Supprimer un élément
1. supprimer tous les éléments :
public final synchronized void removeAllElements() ;
2. supprimer la première occurrence d’un objet :
public final synchronized boolean removeElement(Object obj) ;
3. supprimer un élément à une position donnée :
public final synchronized boolean removeElementAt(int index)
throws ArrayIndexOutOfBoundsException ;
68
11.2. CLASSE FILE
import java.io.File;
public class Ls {
public static void main(String arg[]){
File dir;
for (int i=0;i<arg.length;i++) {
dir = new File(arg[i]);
System.out.println(dir.getAbsolutePath()+":");
String [] r=dir.list();
for (int j=0;j<r.length;j++)
System.out.println("\t"+r[j]);
}
}
}
Exemple 2 : lister les attributs d’un fichier donné sur la ligne de commande (type
(répertoire/fichier), taille, droits d’accès) :
import java.io.File;
public class AttributsFichier {
public static void main(String arg[]){
File dir;
if (arg.length!=1) {
System.out.println("usage : java AttributsFichier <nom_fichier>");
}
else {
dir = new File(arg[0]);
if (dir.isFile()) {
System.out.println(dir.getAbsolutePath()+" est un fichier");
}
else {
System.out.println(dir.getAbsolutePath()+" est un repertoire");
}
System.out.println("taille : "+dir.length()+" octets");
System.out.println("lecture autorisee : "+(dir.canRed()?"oui":"non"));
System.out.println("ecriture autorisee : "+(dir.canWrite()?"oui":"non"));
}
}
}
suit), l’entier limit spécifie le nombre maximum d’octets que l’on peut lire avant
que la marque devienne invalide,
– synchronized void reset() retourne dans le flot à la dernière position marquée
(par la méthodemark()),
– boolean markSupported indique si le flot peut être marqué ou non,
– void close() ferme un flot d’entrée et libère toutes les ressources associées, même
si cela n’est pas vraiment nécessaire, c’est une bonne habitude de faire appel
explicitement à cette méthode.
3. Les méthodes d’écriture :
– void write(int b) écrit l’octet donné sur le flot de sortie,
– void write(byte b[]) écrit les octets du tableau donné sur le flot de sortie,
– public void write(byte b[],int off,int len) écrit len octets du tableau
donné à partir de la position off.
4. Les autres méthodes de OutputStream :
– void flush(), sert plutôt pour les flots bufférisés et force l’écriture du contenu
du buffer,
– void close() ferme un flot de sortie et libère les ressources associées.
Les méthodes des classes Reader et Writer sont similaires à celles de leur correspon-
dantes InputStream et OutputStream. Nous ne les décrivons donc pas en détail.
temps) au clavier. On peut donc utiliser les méthodes de cette classe. On peut aussi le
convertir en un Reader. Pour System.out, qui est une instance de PrintStream, vous
l’avez déjà utilisé, avec ses deux méthodes print et println. Nous n’y reviendrons pas.
L’exemple ci-dessous illustre la lecture au clavier de caractères :
import java.io.*;
class Lecture {
public static void main(String arg[]){
char c;
try {
System.out.print("Saisie :");
c=(char)System.in.read();
System.out.println(" c= "+c);
}
catch (IOException e) {
System.out.println(e.toString());
}
try {
Reader in = new InputStreamReader(System.in);
c=(char)in.read();
System.out.println(" c= "+c);
}
catch (IOException e) {
System.out.println(e.toString());
}
}
}
/*** exemple d’execution ***
Saisie :abcdef
c= a
c= b
Voici un exemple de lecture au clavier d’une chaı̂ne de caractères, utilisant la classe Reader.
import java.io.*;
class Lecture2 {
public static void main(String arg[]){
char buf[]=new char[10];
try {
Reader in = new InputStreamReader(System.in);
in.read(buf,0,5);
String s = new String(buf);
System.out.println("chaine lue :"+s);
}
catch (IOException e) {
System.out.println(e.toString());
}
}
}
import java.io.*;
class Lecture3 {
public static void main(String arg[]){
String s;
BufferedReader in = new BufferedReader( new InputStreamReader(System.in));
try {
s=in.readLine();
System.out.println("chaine lue :"+s);
}
catch (IOException e) {
System.out.println(e.toString());
}
}
}
import java.io.*;
class EcritureBinaire {
public static void main(String arg[]){
try {
FileOutputStream fichier = new FileOutputStream(new File("fichier.dat"));
for (int i=1;i<10;i++) fichier.write(i);
}
catch (IOException e) {
System.out.println(e.toString());
}
}
}
import java.io.*;
class LectEcriture {
import java.io.*;
class Analyse {
public static void main (String[] argv) throws IOException {
int somme=0,nb=0;
int type;
String stop=new String("fin");
System.out.println("Donnez le nom de l’etudiant,
et ses notes, terminez avec fin");
StreamTokenizer entree= new StreamTokenizer
(new InputStreamReader(System.in));
type=entree.nextToken();
if ((type!=StreamTokenizer.TT\_WORD)) {
System.out.println("donnez d’abord le nom !");
}
else {
String nom=entree.sval;
while(true) {
type=entree.nextToken();
if (type==StreamTokenizer.TT\_NUMBER) {
somme+=(int)entree.nval;
nb++;
}
else
if ((type==StreamTokenizer.TT_WORD)&&(stop.equals(entree.sval)))
break;
}
System.out.println("La moyenne de "+nom+" est "+((double)somme/nb));
}
}
}
/******** exemple d’execution
Donnez le nom de l’etudiant, et ses notes, terminez avec fin
machin 10 12
10
sgdb
12
fin
La moyenne de machin est 11.0
La classe java.net.URL représente une URL (i.e. une adresse de ressource sur le Web).
On peut, à partir d’un tel objet, ouvrir une connection et obtenir un flot à partir de l’URL.
L’exemple ci-dessous vous donne une illustration :
import java.net.*;
import java.io.*;
class LectURL {
public static void main(String arg[]) throws MalformedURLException{
String s;
URL monUrl = new URL("http://www.esil.univ-mrs.fr/~chaouiya/Java/Individu.java");
try {
InputStream in1=monUrl.openStream();
BufferedReader in2 = new BufferedReader(new InputStreamReader(in1));
s=in2.readLine();
in2.close();
System.out.println("chaine lue :"+s);
}
catch (IOException e) {
System.out.println(e.toString());
}
}
}
/*** exemple d’execution ***
gbm-server:~/coursJava/Td/ES> java LectURL
chaine lue :class Individu \{
*/
import java.io.*;
import java.util.*;
class SaisieClavier {
public static void main (String[] argv) throws IOException, NumberFormatException {
int somme=0;
String ligne;
StringTokenizer st;
BufferedReader entree =new BufferedReader(new InputStreamReader(System.in);
ligne=entree.readLine();
while(ligne.length() > 0) {
st=new StringTokenizer(ligne);
while(st.hasMoreTokens())
somme+=Integer.parseInt(st.nextToken());
ligne=entree.readLine();
}
System.out.println("La somme vaut : "+somme);
}
}
/******* exemple d’execution
gbm-server:~/coursJava/Td/ES> java SaisieClavier
1 2
3
4
La somme vaut : 10
Autre exemple :
import java.io.*;
import java.util.*;
class SaisieClavier {
Nom Descriptif
Interfaces :
DataInput lecture de types primitifs Java
DataOutput écriture de types primitifs Java
Externalizable, FilenameFilter ObjectInput (hérite de DataInput lecture d’objets
ObjectInputValidation ObjectOutput (hérite de DataOutput) écriture d’objets
Serializable pour la sauvegarde d’objets
Classes :
BufferedInputStream,BufferedOutputStream dans ce chapitre
BufferedReader,BufferedWriter dans ce chapitre
ByteArrayInputStream,ByteArrayOutputStream
CharArrayReader,CharArrayWriter
DataInputStream, DataOutputStream dans ce chapitre
File dans ce chapitre
FileDescriptor dans ce chapitre
FileInputStream, FileOutputStream dans ce chapitre
FileReader, FileWriter dans ce chapitre
FilterInputStream, FilterOutputStream
FilterReader, FilterWriter
InputStream
InputStreamReader
LineNumberInputStream, LineNumberReader
ObjectInputStream ,ObjectOutputStream
ObjectStreamClass
OutputStream, ObjectOutputStream
OutputStreamWriter
PipedInputStream,PipedOutputStream
PipedReader, PipedWriter
PrintStream, PrintWriter
PushbackInputStream,PushbackReader
RandomAccessFile
Reader cf plus loin
SequenceInputStream
StreamTokenizer dans ce chapitre
StringBufferInputStream
StringReader, StringWriter
Writer dans ce chapitre
Exceptions :
CharConversionException,EOFException
FileNotFoundException,IOException
InterruptedIOException, InvalidClassException
InvalidObjectException, NotActiveException
NotSerializableException, ObjectStreamException
OptionalDataException, StreamCorruptedException
SyncFailedException, UTFDataFormatException
UnsupportedEncodingException
WriteAbortedException
Support de cours programmation Java - GBM2 - 80-
Chapitre 12
On présente dans ce chapitre l’essentiel de ce qu’il faut savoir pour développer des
applets qui sont des applications Java qui tournent dans un navigateur. Nous verrons ensuite
comment composer une interface graphique, puis comment la faire fonctionner.
12.1 Introduction
Jusque là, nous avons travaillé avec des applications indépendantes. Il s’agit de pro-
grammes, comparables à ceux écrits dans d’autres langages, dont le point d’entrée est la
méthode main de la classe donnée en argument de la commande java (une application
indépendante est exécutée directement par la JVM) et déclarée comme suit :
public static void main(String [] arg)
81
12.2. CRÉER UNE APPLET
java.lang.Object
java.awt.Component
java.awt.Container
java.awt.Panel
java.applet.Applet
pour une applet pour qu’elle puisse être exécutée dans un navigateur supportant Java. Elle
permet aussi d’utiliser toutes les fonctionnalités d’un composant du paquetage awt.
Bien sûr, votre applet peut faire appel à d’autres classes décrites par ailleurs, mais la
classe initiale de l’applet doit avoir une signature comme suit :
public class monApplet extends java.applet.Applet ...
Notez que le mot clé public est ici indispensable pour la classe principale de votre applet,
par contre les classes utilisées que vous créez ne sont pas nécessairement déclarées publiques.
Quand un navigateur rencontre votre applet dans une page Web, il va charger votre classe
initiale à travers le réseau, ainsi que les autres classes utilisées au fur et à mesure des
besoins. Cela peut entraı̂ner des pertes de performances (pour éviter cette perte de temps
en chargement à travers le réseau, une solution consiste à utiliser des archives...)
C’est la classe Applet qui donne les prototypes des méthodes init, start, stop,
destroy.
Exemple : fichier Bonjour.java
import java.applet.*;
import java.awt.*;
public class Bonjour extends Applet {
public void paint(Graphics g) {
g.setFont(new Font("TimesRomman",Font.BOLD,30));
g.setColor(Color.blue);
g.drawString("Bonjour !",50,50);
}
}
<APPLET
CODE="MonApplet.class"
WIDTH = taille_en_pixels
HEIGHT = taille_en_pixels
</APPLET>
– l’attribut CODE donne le nom du fichier (extension .class) contenant l’applet. S’il
ne se trouve pas dans le même répertoire que le fichier HTML, il faudra utiliser
l’attribut CODEBASE décrit plus loin,
– les attributs WIDTH et HEIGHT sont nécessaires et donnent la taille de la boı̂te réservée
à l’affichage de votre applet sur la page Web,
– le texte entre les balises <APPLET> et </APPLET> est affiché par les navigateurs qui
ne comprennent pas ces balises (notamment ceux qui ne supportent pas les applets),
il est donc bon de prévoir un petit message pour que vos lecteurs qui n’ont pas de
navigateurs supportant Java, voient autre chose qu’une ligne blanche muette...
La balise <APPLET> a été présentée ci-dessus dans sa forme minimale. Ellea en fait plus de
fonctionnalités (pour beaucoup, identiques à celles de la balise <IMG>) :
– l’attribut ALIGN définit comment l’applet doit être alignée dans la page, il peut
prendre une des valeurs suivantes : LEFT, RIGHT, TOP, TEXTTOP, MIDDLE, ABSMIDDLE,
BASELINE, BOTTOM, ABSBOTTOM,
– les attributs HSPACE et VSPACE sont utilisés pour définir un espace entre l’applet et
le texte qui l’entoure,
– l’attribut CODEBASE permet de spécifier le répertoire ou l’URL où trouver l’applet, si
elle n’est pas au même endroit que le fichier HTML de la page la contenant.
Enfin, il est possible de passer des paramètres à l’applet. Cela se fait avec la balise
<PARAM NAME=nom parametre VALUE=valeur parametre> placée dans le champ de la ba-
lise >APPLET>.
Exemple : une applet qui affiche le texte qu’on lui passe en paramètre (fichier Texte.java),
et le fichier HTML permettant de charger cette applet
– fichier Texte.java :
import java.applet.*;
import java.awt.*;
public class Texte extends Applet {
String leTexte;
public void init(){
leTexte=getParameter("le_texte");
}
public void paint(Graphics g) {
g.setFont(new Font("mafonte",Font.ITALIC,30));
g.setColor(Color.blue);
g.drawString(leTexte,50,50);
}
}
– fichier Texte.html
<HTML>
<HEAD>
<TITLE>Applet simple qui affiche un texte</title>
</HEAD>
<BODY>
<h1>Applet simple qui affiche un texte</h1>
<APPLET
CODE = "Texte.class"
WIDTH=300 HEIGHT = 200>
<PARAM NAME=le_texte VALUE="Bonjour !">
Votre navigateur ne supporte pas Java ?! Bonjour quand meme !
</APPLET>
</BODY>
</HTML>
Autres exemples :
– L’exemple ci-dessous illustre le cycle de vie d’une applet :
/******* le fichier java *******/
import java.awt.*;
import java.applet.*;
import java.util.*;
public class Affiche extends Applet {
public Vector lesAppels;
public void init() {
lesAppels=new Vector();
lesAppels.addElement("init");
}
public void start(){
lesAppels.addElement("start");
}
public void stop(){
lesAppels.addElement("stop");
}
public void paint(Graphics g) {
lesAppels.addElement("paint");
Enumeration e=lesAppels.elements();
int y=15;
while(e.hasMoreElements()) {
g.drawString((String)e.nextElement(),20,y);
y+=10;
}
}
}
/******* le fichier HTML ******/
<html>
<head>
<title>Premiére Applet</title>
</head>
<body>
<h1>Premiére Applet</h1>
<applet
code = "Affiche.class" width=300 height = 200>
</applet>
</body>
</html>
– un petit exemple qui illustre quelques unes des méthodes de la classe java.awt.Graphics :
import java.awt.*;
import java.applet.*;
public class ParamGraphic extends Applet {
public void init() {
String couleur = getParameter("couleur");
}
public Color rendCouleur(String s)
{
if (s==null)return Color.black;
else if (s.equals("rouge")) return Color.red;
else if (s.equals("vert")) return Color.green;
else if (s.equals("bleu")) return Color.blue;
else if (s.equals("magenta")) return Color.magenta;
else if (s.equals("pink")) return Color.pink;
else if (s.equals("orange")) return Color.orange;
else if (s.equals("cyan")) return Color.cyan;
else if (s.equals("yellow")) return Color.yellow;
return Color.black;
}
public void paint(Graphics g) {
g.drawString((String)getParameter("titre"),20,10);
g.setColor(rendCouleur((String)getParameter("couleur")));
g.fillRect(30,30,100,100);
g.fillOval(130,130,40,40);
}
}
/******* le fichier HTML *********/
<html>
<head>
<title>Un exemple tout simple</title>
</head>
<body>
<h1>Un exemple tout simple</h1>
<applet
code = "ParamGraphic.class" width=400 height = 300>
<PARAM NAME=couleur VALUE="bleu">
<PARAM NAME=titre VALUE="comment passer des paramètres">
</applet>
</body>
</html>
– void showDocument(URL url) : remplace la page Web par celle référencée par l’URL
donnée en paramètre.
Vous avez franchi la première étape qui consiste à comprendre comment fonctionnent
les applets. Il faut maintenant se familiariser avec les outils fournis par Java pour dessiner
sur la page, actualiser le contenu de la page, gérer les événements souris et clavier, créer
des éléments d’interface utilisateur.
Attention, toutes les interfaces que vous serez amenés à écrire ne seront pas nécessairement
incluses dans une applet, elles peuvent très bien être liées à une application indépendante.
On pourra consulter dans l’annexe ?? des diagrammes représentant la hiérarchie des classes
du paquetage java.awt.
88
13.1. CLASSE JAVA.AWT.GRAPHICS
(0,0) X
-
Component
(width-1,height-1)
Y
?
h
6hg
"
? -!
?
lg
Méthode Description
drawLine(x1,y1,x2,y2) ligne droite de (x1,y1)à (x2,y2)
drawRect(x,y,l,h) rectangle vide, (x,y) coin sup.gauche, largeur l, hauteur h
fillRect(x,y,l,h) rectangle plein, (x,y) coin sup.gauche, largeur l, hauteur h
drawRoundRect(x,y,l,h,lg,hg) rectangle vide à coins arrondis,(x,y) coin sup.gauche,
largeur l, hauteur h, angle largeur lg, hauteur hg
fillRoundRect(x,y,l,h,lg,hg) rectangle plein à coins arrondis, ...
draw3DRect(x,y,l,h,bool) rectangle vide effet 3D en relief (bool=true) ou enfoncé (bool=false)
draw3DRect(x,y,l,h,bool) rectangle plein effet 3D...
drawPolygon(tabX,tabY,n) polygone vide à n sommets, tabX tableau abscisses, tabY ordonnées
fillPolygon(tabX,tabY,n) polygone plein à n sommets, tabX, tableau abscisses, tabY ordonnées
drawPolygon(polyg) polygone vide défini par l’instance de Polygon
fillPolygon(polyg) polygone plein défini par l’instance de Polygon
drawOval(x,y,l,h) ovale vide délimité par le rectangle défini par x,y,l et h
fillOval(x,y,l,h) ovale plein délimité par le rectangle défini par x,y,l et h
Bien sûr, on peut aussi spécifier la couleur de fond du composant graphique grâce à
la méthode setBackground(laCouleur) de la classe java.awt.Component (dont hérite la
classe Applet).
Le dernier exemple du chapitre 12 vous donne un exemple illustrant l’utilisation des
couleurs.
13.2.1 Conteneurs
Pour pouvoir placer les composants il faut un conteneur. Tous les conteneurs héritent
de la classe java.awt.Container. Les deux principaux sont :
– la classe Window qui crée une nouvelle fenêtre, ses classes dérivées Frame (fenêtre
avec un bord et une barre de menu) et Dialog (fenêtre pour le choix d’une fichier
par exemple) sont également très utiles,
– la classe Panel est la classe mère de la classe Applet. Elle propose un espace dans
lequel une application peut placer des composants mais aussi d’autres panneaux.
Par défaut les composants sont ajoutés de gauche à droite et de haut en bas. Il existe
des gestionnaires pour gérer le placement des composants, ce sont les LayoutManager(cf.
13.3).
13.2.2 Composants
On les appelle aussi des widgets(pour WInDows gadGET), ce sont des composants
graphiques que l’on peut ajouter dans des conteneurs.
1. Label pour afficher du texte qui ne doit pas changer,
2. TextField pour une zone de saisie d’une ligne de texte,
3. TextArea pour une zone de saisie d’un paragraphe,
4. Button pour un bouton,
5. Checkbox pour une case à cocher,
6. CheckboxGroup pour un groupe de cases à cocher,
7. Choice pour une liste de choix, List pour une liste défilante,
8. Scrollbar pour un ascenseur,
Exemple :
import java.applet.Applet;
import java.awt.*;
public class AjoutComposants extends Applet {
private Label l=new Label("Titre");
private TextField t1=new TextField("Entrez ici votre nom");
private Button b = new Button("appuyer ici");
private Checkbox c1= new Checkbox("oui");
private Checkbox c2= new Checkbox("non");
private CheckboxGroup grp= new CheckboxGroup();
private List liste = new List(3,false);
private Scrollbar sb = new Scrollbar(Scrollbar.HORIZONTAL,30,500,0,1000);
add(c1);
c2.setState(false);
c2.setCheckboxGroup(grp);
add(c2);
liste.addItem("d’accord");
liste.addItem("pas d’accord");
liste.addItem("ne sais pas");
add(liste);
add(sb);
}
}
import java.applet.Applet;
import java.awt.*;
public class Disposition extends Applet {
private Button b1 = new Button("bouton1");
private Button b2 = new Button("bouton2");
private Button b3 = new Button("bouton3");
private Button b4 = new Button("bouton4");
private Panel p = new Panel();
public void init(){
setLayout(new BorderLayout(2,2));
add("North",b1); add("West",b2);
add("East",b3); add("South",b4);
add("Center",p);
}
public void paint(Graphics g) {
Graphics g2=p.getGraphics();
g2.setColor(Color.blue);
g2.drawOval(10,10,30,30);
}
}
==============================================
import java.applet.Applet;
import java.awt.*;
public class Disposition2 extends Applet {
private Button b1 = new Button("bouton1");
private Button b2 = new Button("bouton2");
private Button b3 = new Button("bouton3");
private Button b4 = new Button("bouton4");
public void init(){
setLayout(new BorderLayout(2,2));
add("North",b1);
add("West",b2);
add("East",b3);
add("South",b4);
}
}
14.1 Introduction
Nous avons l’habitude d’écrire des programmes séquentiels : à partir d’un point de
départ(la méthode main pour une application autonome), la machine exécute des instruc-
tions, les unes après les autres. Dans ce chapitre, les applications qui nous intéressent
sont d’une autre nature, elles n’ont pas un unique fil d’exécution mais plusieurs, qui se
déroulent en parallèle (ou du moins semblent le faire). On appelle thread un fil d’exécution,
on parle aussi de processus léger. Les processus légers sont internes à une même appli-
cation et partagent donc le même espace d’adressage, alors que les processus lourds (ou
processus) sont gérés par le système d’exploitation qui leur alloue à chacun un espace de
travail. La programmation concurrente suppose des mécanismes de synchronisation et
d’exclusion mutuelle. Ces mécanismes sont présents dans le langage Java qui permet
donc de programmer facilement l’exécution concurrente de plusieurs threads. Ce n’est pas
le cas des langages classiques pour lesquels la programmation concurrente est une affaire
de spécialistes !
Les threads se trouvent, à tout instant, dans un état particulier :
– instancié (New Thread),
– actif (running)
– endormi (not running),
– mort (dead).
96
14.2. CLASSE THREAD ET L’INTERFACE RUNNABLE
running
' $
yield
-
Not Runnable
New Thread start - ?
Runnable
fin de la méthode run
?
Dead
leThread.start();
La méthode start() alloue les ressources nécessaires à l’exécution d’un thread et invoque
la méthode run() de l’objet passé en paramètre lors de l’instanciation du thread. Rendre
un thread actif ne signifie pas qu’il va s’exécuter en continu jusqu’à la fin. Il rejoint le
groupe des threads actifs et le système se charge d’allouer régulièrement une tranche de
temps pour qu’il puisse exécuter ses instructions.
Premier exemple :
processus doit être spécifié “à la main”. Dans le cas d’applets qui définissent des animations
graphiques, celles-ci n’ont pas lieu d’être exécutées si la page HTML qui contient l’applet
n’est temporairement pas visible.
Les méthodes suspend et resume : La méthode suspend() doit être utilisée avec
précaution, car il faut s’assurer que l’application invoque la méthode resume() ou la
méthode stop() pour rendre le thread actif ou pour le tuer. Ces méthodes sont depre-
cated.
La méthode sleep : Une solution pour suspendre l’exécution d’un thread consiste à
l’endormir pendant un certain temps. Dans le cas d’une animation graphique, pour éviter
un affichage trop rapide, on utilise la méthode sleep(tps) pour suspendre l’exécution pen-
dants un laps de temps passé en paramètre et exprimé en millisecondes. La méthode sleep
lance l’exception InterruptedException si le thread est stoppé pendant son sommeil.
L’invocation de cette méthode doit donc gérer cette exception.
L’exemple tic-tac est modifié ci-dessous pour forcer chacun des threads à s’endormir
régulièrement de façon que l’autre puisse s’exécuter :
this.s=s;
}
public void run() {
while (true) {
System.out.println(s);
try { sleep(100);}
catch(InterruptedException e){}
}
}
}
public class TicTac4 {
public static void main(String arg[]){
TestThread tic=new TestThread("TIC");
TestThread tac=new TestThread("TAC");
tic.start();
tac.start();
}
}
class Reunion {
public static void main(String[] arg){
Megaphone m=new Megaphone();
Orateur o1=new Orateur("Orateur 1","je suis le premier !",m);
Orateur o2=new Orateur("Orateur 2","je suis le deuxième !",m);
Orateur o3=new Orateur("Orateur 3","je suis le troisième !",m);
o1.start();o2.start();o3.start();
}
}
Une méthode d’instance synchronized pose un verrou sur l’objet par lequel elle a
été invoquée. Une méthode statique (de classe) peut être qualifiée de synchronized.
Elle pose alors un verrou sur la classe et ainsi, deux méthodes statiques synchronized
ne peuvent être exécutées en même temps. Mais attention, il n’y a aucun lien entre les
verrous de classes et les verrous d’instances. Une classe verrouillée (par une méthode sta-
tique synchronized) n’empêche pas l’exécution d’une méthode d’instance synchronized
et inversement.
Avec le mot clé synchronized on a vu comment verrouiller une instance sur toute une
méthode. En fait, il est possible de ne verrouiller qu’une partie du code d’une méthode.
L’instruction comporte alors deux parties : l’objet à verrouiller et la ou les instructions à
exécuter :
synchronized(objet)
instruction-simple-ou-bloc-d’instructions
L’exemple qui suit reprend le cas du mégaphone, qui signale quand un orateur a de-
mandé à l’utiliser :
Lorsque la méthode wait est invoquée à partir d’une méthode synchronized, en même
temps que l’exécution est suspendue, le verrou posé sur l’objet par lequel la méthode a été
invoquée est relâché. Dès que la condition de réveil survient, le thread attend de pouvoir
reprendre le verrou et continuer l’exécution. Notez qu’une autre version de wait prend en
argument un entier de type long qui définit la durée d’attente maximale (en millisecondes).
Si ce temps est dépassé, le thread est réveillé.
La méthode notify réveille un seul thread. Si plusieurs threads sont en attente, c’est
celui qui a été suspendu le plus longtemps qui est réveillé. Lorque plusieurs threads sont
en attente et qu’on veut tous les réveiller, il faut utiliser la méthode notifyAll. L’exemple
qui suit est une adaptation du précédent avec des orateurs qui interrompent leur discours
de temps en temps et libèrent le mégaphone pour les orateurs en attente. Voilà une réunion
plus conviviale ! !
class Megaphone {
synchronized void parler(String qui, String quoi, Thread t) {
System.out.println("mégaphone demandé par orateur "+qui);
for (int i=1; i<=10; i++){
System.out.println(qui+" affirme : "+quoi);
notifyAll(); // libère le mégaphone
try{wait();} // se met en attente
catch(InterruptedException e){ }
}
}
}
L’exemple qui suit est celui classique du producteur et du consommateur qui produisent
et consomment dans un même buffer :
import java.util.*;
class Buffer extends Stack {
public synchronized void poser(char donnee) {
// attendre tant que le buffer est plein
while (full()) {
try {
wait(); // mise en attente
}
catch(Exception e) {}
}
// au moins une place libre
push(new Character(donnee));
notify(); // fin de mise en attente
}
public synchronized char prendre(){
// attendre tant que le buffer est vide
while (empty()){
try{
wait(); // mise en attente
}
catch(Exception e){}
}
notify();
return ((Character)pop()).charValue();
}
public boolean full() {return (size()==2);}
public boolean empty() {return (size()==0);}
}
class Producteur extends Thread {
private Buffer buffer;
private String donnee;
public Producteur(Buffer buffer, String donnee) {
this.buffer=buffer;
this.donnee=donnee;
}
public void run(){
for (int i=0;i<donnee.length();i++) {
// produire les donnees
buffer.poser(donnee.charAt(i));
try {
// rythme de production aleatoire
sleep((int) (Math.random()*25));
}
catch(Exception e){}
}
System.out.println("\nProduction terminee");
}
}
class Consommateur extends Thread {
private Buffer buffer;
private int nombre;
public Consommateur(Buffer buffer, int nombre) {
this.buffer=buffer;
this.nombre=nombre;
}
public void run(){
for (int i=0;i<nombre;i++) {
// consommer les donnees
char car= buffer.prendre();
System.out.print(car);
try {
// rythme de consommation aleatoire
sleep((int) (Math.random()*100));
}
catch(Exception e){}
}
System.out.println("\nConsommation terminee");
}
}
public class ProdCons {
public static void main(String arg[]) {
String donnee="Java est un langage merveilleux !";
Buffer buffer=new Buffer();
Producteur producteur = new Producteur(buffer,donnee);
Consommateur consommateur=new Consommateur(buffer,donnee.length());
producteur.start();
consommateur.start();
}
}
import java.awt.*;
import java.awt.event.*;
import java.util.*;
if (e.getSource()==fenetre){
System.exit(0);
}
}
}
EssaiGestionThread() {
tracer.addActionListener(this);
pauser.addActionListener(this);
stopper.addActionListener(this);
effacer.addActionListener(this);
add(tracer);
add(pauser);
add(stopper);
add(effacer);
alea = new Random((new Date()).getTime());
setVisible(true);
}
public void actionPerformed(ActionEvent evt) {
Object source = evt.getSource();
if (source == tracer) {
int debut= (int)Math.abs(alea.nextLong());
if ((thread == null)||(!thread.isAlive())) {
thread = new RondsConcentriques(debut, this);
thread.start();
}
else thread.reprendre();
}
else if ((source == pauser) && (thread != null))
thread.suspendre();
else if (source == stopper) {
if (thread != null) thread.stopper();
thread = null;
}
else if (source == effacer) repaint();
}
public static void main(String[] argv) {
Frame f = new Frame();
f.addWindowListener(new Ecouteur(f));
f.setSize(500,500);
f.add(new EssaiGestionThread());
f.setVisible(true);
}
}
XXX
XX
stop()
XXX
z
Créé Mort .
""
-
"
"
"
" notifyAll()
start() " H H H notify()
" HH délai wait écoulé
stop() "
"
H
? " H
Exécutable
6 resume() Z En attente
Q délai sleep
Z
écoulé
Z :.
Q obj.déverrouillé Z wait()
Q
yield() 6 Z
?
QQ
Z
QQ
Thread courant Bloqué
:
QQ
A suspend()
sleep()
A stop()
A
A fin de run() obj.verrouillé
A
A
VIVANT