Langage à Objets : java - webia.lip6.frwebia.lip6.fr/~auzende/enseignements/java.pdf · Exemples...

38
DU TICE Langage à Objets : java O. Auzende 2010

Transcript of Langage à Objets : java - webia.lip6.frwebia.lip6.fr/~auzende/enseignements/java.pdf · Exemples...

DU TICE

Langage à Objets : java

O. Auzende 2010

2

LANGAGE A OBJETS : JAVA .................................................................................. 3

1. INTRODUCTION .................................................................................................... 3

2. ELEMENTS DE PROGRAMMATION JAVA .......................................................... 4

3. JAVA, LANGAGE A OBJETS ............................................................................. 10

4. LES PAQUETAGES JAVA .................................................................................. 13

5. LE PAQUETAGE GRAPHIQUE JAVA.AWT ....................................................... 16

6. LA GESTION DES EVENEMENTS ...................................................................... 20

7. LES APPLETS JAVA ........................................................................................... 25

ANNEXES ................................................................................................................ 38

Langage à Objets : Java

3

Langage à objets : java

1. Introduction

Langages compilés Lorsqu’un langage informatique est destiné à être compilé, un compilateur dédié au langage examine le code source. Ce compilateur contrôle si le code source vérifie la syntaxe du langage utilisé. Si c’est le cas, le compilateur (sauf le compilateur java) génère un fichier en langage machine, dit “code objet” exécutable sur tout ordinateur du même type que celui sur lequel on a effectué la compilation. Exemples de langages compilés : Pascal, Cobol, C, C++ Avantage : le code objet s’exécute très rapidement, ce qui est indispensable pour les applications économiques ou industrielles. Inconvénients : la mise au point des programmes est délicate (en cas de plantage pendant l’exécution, où est l’erreur ?), le compilateur dépend du type d’ordinateur sur lequel on travaille et surtout le code objet est dédié au type de machine sur lequel on a compilé.

Langages interprétés Lorsqu’un langage est interprété, l’interpréteur ne traduit pas globalement le fichier source en un fichier exécutable. Il lit au contraire le fichier source ligne à ligne, vérifie chaque instruction et ne l’exécute que si elle est correcte. Exemples de langages interprétés : HTML, JavaScript, Perl, PHP. Avantages : l’interpréteur s’arrête en cas d’erreur sur la ligne erronée ; le “débuguage” est donc facilité. Le type de machine qui interprète le fichier n’est pas forcément le même que celui sur lequel on a tapé le fichier source. Il suffit de disposer de l’interpréteur adéquat sur la machine destinataire. Un programme écrit en langage interprété est donc portable. Inconvénient : la vérification ligne à ligne du code source cause une lenteur certaine à l’exécution.

Java, compilé et interprété Java est un langage développé par la société SUN en 1995 pour assurer la portabilité des programmes sur une large gamme de machines. Sur l’ordinateur sur lequel on écrit un programme Java, le code source est transformé par le compilateur javac (de la machine sur laquelle on travaille) en un « pseudo-code » non exécutable, qui est le même quel que soit le type d’ordinateur sur lequel on travaille. Transféré sur un autre type d’ordinateur, le pseudo-code est interprété par l’interpréteur java (de la machine sur laquelle on travaille), qui ne vérifie plus la syntaxe des instructions mais exécute directement le pseudo-code. Avantages : le pseudo-code est indépendant du type d’ordinateur sur lequel il a été créé et du type d’ordinateur sur lequel il va être exécuté. Il est donc por table. De plus, lors de la compilation, le code des bibliothèques utilisées n’est pas intégré dans le pseudo-code ; seul le bon usage de ces bibliothèques est vérifié à la compilation. Mais le code des bibliothèques utilisées est chargé à l’exécution. Le pseudo-code est donc de faible taille, et circule rapidement sur les réseaux.

Utilisation de java Applications : programmes classiques, analogues à ceux créés avec d’autres langages, compilés puis interprétés. Applets : petits programmes compilés, dont le pseudo-code est appelé dans une page HTML par une balise spécifique <APPLET>. L’interpréteur java intégré dans chaque navigateur (Internet Explorer, Netscape) interprète le pseudo-code. Servlets : programmes exécutés sur le serveur, permettant de générer des pages Web dynamiques. C’est une alternative aux scripts CGI, aux pages ASP et PHP.

4

2. Eléments de programmation Java

Notion de variable La notion de var iable en informatique est assez proche de la notion mathématique. En mathématiques, x = 5 veut dire que la variable x vaut 5. En informatique, x est le contenu d’un emplacement-mémoire dont la taille (nombre de bits qui composent cet emplacement) dépend de ce qu’on veut y stocker (un caractère prend moins de place qu’un entier, un entier prend moins de place qu’un réel…). Le contenu de cet emplacement-mémoire peut constamment être changé. On précise donc (syntaxe java) :

int x ; (réservation de place-mémoire pour un entier) x = 5 ; (on y met la valeur 5) x = 7 ; (on remplace 5 par 7 dans le même emplacement mémoire) float y ; (réservation de place-mémoire pour un réel) y = 3.5 ; (on y met la valeur 3.5)

Ces lignes peuvent être résumées en :

int x = 5 ; x = 7 ; (réservation de place-mémoire pour un entier. On y met la valeur 5 puis 7) float y = 3.5 ; (réservation de place-mémoire pour un réel et on y met la valeur 3.5)

Affectation Les instructions x = 5 ; x = 7 ; y = 3.5 ; donnent des valeurs aux emplacements-mémoire x et y. Ces instructions sont appelées des affectations.

L’écriture a = b correspond à a b et doit se lire a “reçoit” la valeur de b. On peut affecter à une variable x : o une valeur : x = 5 ; o la valeur d’une autre variable : y = 3 ; x = y ; o le résultat du calcul d’une expression : y = 3 ; z = 4 ; x = y + z ;

Egalité, inégalité Le symbole = étant réservé à l’affectation, on teste l’égalité

if (a == b) … qui se lit : si (a = b) ... de deux variables a et b en écrivant :

On teste l’inégalité

if (a != b) … qui se lit : si (a ≠ b) ... de deux variables a et b en écrivant :

Conjonction, disjonction La conjonctionAinsi, tester si (a=b) et (c=d) s’écrit : if ((a==b) && (c==d))

ET s’écrit &&

La disjonctionAinsi, tester si (a=b) ou (c=d) s’écrit : if ((a == b) | | (c == d))

OU s’écrit | |

Types de données primitifs en Java En Java, il y a 8 types de données primitifs. Ce sont les types : o boolean : true et false o char : caractère o byte : petit entier stocké sur 8 bits o short : entier court stocké sur 16 bits o int : entier “normal” stocké sur 32 bits o long : entier long stocké sur 64 bits o float : réel simple stocké sur 32 bits o double : réel double précision stocké sur 64 bits

Langage à Objets : Java

5

L’instruction boolean fini = false ; définit une variable fini de type booléen et de valeur false. L’instruction int i = 254256 ; définit une variable i de type entier, stockée sur 32 bits et de valeur 254256. L’instruction long l = 25425645987 ; définit une variable l de type entier long, stockée sur 64 bits et de valeur 25425645987. L’instruction float f = 156.256 ; définit une variable f de type flottant, stockée sur 32 bits et de valeur 156.256. L’instruction double t = 0.02635 ; définit une variable t de type réel, stockée sur 64 bits et de valeur 0.02635

Opérateurs de cast L’opérateur de “cast” force la conversion d’un type de données en un autre. Selon le cas, on peut perdre de la précision. Exemples : float f = 156.256 ; int j = (int) f ; j est alors un entier valant 156 double t = 0.02635; float d = (float) t; t est stocké sur 64 bits, d est stocké sur 32 bits

Première application Java 1) Ouvrez avec WordPad ou le bloc-notes le fichier Programme.java (attention, première lettre en majuscule)

qui se trouve dans le dossier programme. Comme tous les fichiers source java, c’est un fichier sauvegardé en format texte uniquement

. Son contenu est :

public class Programme { public static void main(String args[]) { int a=25; int b=76; System.out.println("a vaut : " + a); System.out.println("b vaut : " + b); } }

Tout programme java est nécessairement contenu dans une classe. Lorsque le programme ne comporte qu’une seule classe, celle-ci est déclarée public afin d’être accessible à tout utilisateur. Le programme proprement dit figure dans une méthode appelée main nécessairement déclarée sous la forme : public static void main(String[] args) Tout programme contenant une méthode main est une application. Remarques o static indique que main est une méthode de classe (il y a d’autres types de méthodes) o String[] args permet de passer des informations à la méthode main, sous forme d’un tableau de

chaînes de caractères de type String[]. On utilise cette possibilité quand on veut passer des paramètres à la méthode main.

o System.out.println(chaîne) fait afficher à l’écran la chaîne de caractères. Pour construire une chaîne à partir de plusieurs morceaux, on utilise le signe +

Compilation : commande javac Programme.java (création du pseudo-code) Exécution : commande java Programme (interpréation du pseudo-code) 2) Ajoutez au main de la classe Programme les lignes permettant de déclarer deux entiers c et d, de calculer

c=a+b et d=a*b, puis de faire afficher les valeurs de c et de d. Compilez et faites exécuter le fichier ainsi modifié.

3) On voudrait à présent que a, b, c et d puissent être des réels de type primitif double et non plus des entiers.

Modifiez la classe Programme en conséquence, en prenant cette fois a=4.56 et b=-8.65. Compilez le fichier Programme.java ainsi modifié et faites-le exécuter.

4) On veut faire afficher en fin de programme « valeur entiere de d : » puis la partie entière de d. Utilisez un

opérateur de cast pour obtenir ce résultat. Compilez le fichier Programme.java ainsi modifié et faites-le exécuter.

6

Les tests Les tests permettent de faire des traitements différenciés.

Le test simple : if … else Il s’écrit :

if (test) { instructions; } else { instructions; }

La clause else est facultative. On peut avoir simplement : if (test) { instructions ; }

Exemple : public class Programme1 {

public static void main(String[] args) { int a = 25 ; int b = 76 ; System.out.println("a = " + a); System.out.println("b = " + b); int min ; if (a < b) { min = a; } else { min = b; } System.out.println("le minimum de a et b est " + min); }

}

Le test multiple : switch Il s’écrit :

switch (variable) { case 1: instructions; case 2: instructions; ... default : instructions; }

La variable testée doit être de type int Le cas default sert si l’on veut prévoir un traitement par défaut. L’emploi de break dans les instructions signale que le cas est traité et que l’on passe toutes les autres possibilités (on saute les autres cas ).

Exemple : public class Programme1b {

public static void main(String[] args) { int num = 11 ; String mois = "" ; // type chaîne de caractères switch(num) { case 1 : mois="janvier"; break ; case 2 : mois="fevrier"; break ; case 3 : mois="mars"; break ; case 4 : mois="avril"; break ; case 5 : mois="mai"; break ; case 6 : mois="juin"; break ; case 7 : mois="juillet"; break ; case 8 : mois="aout"; break ; case 9 : mois="septembre"; break ; default : mois="au dernier trimestre"; } System.out.println("le mois est " + mois); }

}

Tableaux Les tableaux sont des collections de variables de même type, en nombre fixé. On doit d’abord les déclarer , puis faire l’allocation de mémoire nécessaire avant de les utiliser. Exemples : int [] t ; // déclaration d’un tableau d’entiers t t = new int[20] ; // création de t en mémoire char [] tab ; // déclaration d’un tableau tab de caractères tab = new char[40] ; // création de tab en mémoire String [] t1 ; // déclaration d’un tableau t1 de chaînes t1 = new String[10] ; // création de t1 en mémoire

Langage à Objets : Java

7

On accède à l’élément d’indice i de t par t[i], les indices commençant à 0. Une fois qu’un tableau est créé, sa taille ne peut plus être changée. Exemple : le programme tableau.java du dossier tableau crée un tableau des mois de l’année et le fait afficher. public class Tableau { public static void main(String[] args) { String[] t = new String[12] ; t[0]="janvier"; t[1]="fevrier"; t[2]="mars"; t[3]="avril"; t[4]="mai"; t[5]="juin";t[6]="juillet"; t[7]="aout"; t[8]="septembre"; t[9]="octobre"; t[10]="novembre"; t[11]="decembre"; System.out.println("Les mois de l'annee sont : "); System.out.println(t[0]); System.out.println(t[1]); System.out.println(t[2]); System.out.println(t[3]); System.out.println(t[4]); System.out.println(t[5]); System.out.println(t[6]); System.out.println(t[7]); System.out.println(t[8]); System.out.println(t[9]); System.out.println(t[10]); System.out.println(t[11]); } }

Les boucles La boucle for La boucle for permet de répéter un certain nombre de fois des instructions. Elle s’écrit : for (initialisation; test_continuation; incrémentation) {instructions;} o L’initialisation permet de préciser la variable qui contrôle la boucle et de l’initialiser. Exemple : int i=0 o Le test de continuation dit quel est le test qui doit être vérifié pour que la boucle continue. Exemple : i < 20 o L’incrémentation précise comment évolue la variable de contrôle. Généralement on écrit i++ qui veut dire

i=i+1 (on passe de i à i+1, donc d’une valeur de la variable à la suivante). Exemple : le fichier Tableau1.java du dossier tableau permet de réduire les instructions d’affichage à une seule boucle : public class Tableau1 { public static void main(String[] args) { String[] t = new String[12] ; t[0]="janvier"; t[1]="fevrier"; t[2]="mars"; t[3]="avril"; t[4]="mai"; t[5]="juin"; t[6]="juillet"; t[7]="aout"; t[8]="septembre";t[9]="octobre";t[10]="novembre"; t[11]="decembre"; System.out.println("Les mois de l'annee sont : "); for (int i = 0 ; i < 12; i++) { System.out.println(t[i]); } } }

Dans le programme Tableau2.java du dossier tableau, on utilise deux boucles for : une pour initialiser le tableau, l’autre pour le faire afficher : public class Tableau2 { public static void main(String[] args) { double[] t = new double[20] ; for (int i = 0 ; i < 20 ; i++) { t[i] = i ; } for (int i = 0; i < 20 ; i++) { System.out.print(t[i] + " * "); } } }

La variable i est déclarée dans chaque boucle. o Entre les deux boucles, i n’existe pas o On dit que sa portée se limite à la boucle en cours

8

Dans le programme Tableau2b.java du dossier tableau, la variable i est déclarée dans le main. o La portée de i est alors la méthode main toute entière (i est connu dans tout le main). public class Tableau2b { public static void main(String[] args) { double[] t = new double[20] ; int i ; for (i = 0 ; i < 20 ; i++) { t[i] = i ; } for (i = 0; i < 20 ; i++) { System.out.print(t[i] + " * "); } System.out.println("\n ---> i vaut maintenant " + i) ; } }

La boucle while La boucle while permet de répéter des instructions tant qu’un test est vérifié. Elle s’écrit :

while (test) { instructions ; }

Les instructions doivent modifier au moins une variable intervenant dans le test, pour que le while ne boucle pas indéfiniment.

Exemple : afficher les éléments d’un tableau de nombres t tant que ces éléments sont inférieurs à 20. int i = 0 ; while (t[i] < 20) { System.out.print(t[i] + " ") ; i++ ; } Dans cet exemple, i est modifié dans les instructions, donc t[i] correspond à chaque passage à un élément différent du tableau t. Attention cependant à ne pas dépasser la taille du tableau ! Si le tableau est de taille n, il faut écrire : int i = 0 ; while ((i < n) && (t[i] < 20)) { // && est la notation pour ET System.out.print(t[i] + " ") ; i++ ; }

La boucle do … while Elle permet de faire exécuter une première fois des instructions puis de recommencer tant qu’un test est vérifié.

Elle s’écrit :

do { instructions ; } while (test);

Ces instructions doivent modifier au moins une variable du test, pour que le do … while ne boucle pas indéfiniment.

Exemple : afficher le 1er élément du tableau t, puis les suivants tant qu’ils sont inférieurs au premier : int i = 0 ; do { System.out.print(t[i]+ " "); i++ ; } while ((i<n)&&(t[i]<t[0]));

Les sauts Le break L’instruction break permet de sauter tous les cas suivants, en reprenant l’exécution directement après le test ou la boucle (on saute donc tous les cas suivants). Exemple : afficher les éléments du tableau t tant qu’ils sont inférieurs à 20. On arrête donc dès qu’on rencontre un élément supérieur ou égal à 20.

Langage à Objets : Java

9

for (int i = 0 ; i < n ; i++) { if (t[i]<20) { System.out.print(t[i]+" * "); } else { break ; } }

C’est équivalent à la boucle while ci-dessous : int i = 0 ; while ((i<n) && (t[i] < 20)) { System.out.print(t[i]+" * ") ; i++ ; }

Le continue L’instruction continue permet de sortir d’un pas d’itération en reprenant l’exécution à l’itération suivante. On arrête donc les instructions de l’itération en cours pour passer directement à la suivante. Exemple : afficher tous les éléments du tableau t qui sont différents de 20. Deux versions, selon que l’on teste si t[i] est égal à 20 ou est différent de 20 : for (int i = 0 ; i < n ; i++) { if (t[i] == 20) { continue ; } else {

System.out.print(t[i]+" * "); }

}

for (int i = 0 ; i < n ; i++) { if (t[i] != 20) { System.out.print(t[i]+ " * "); } else { continue ; } }

Le return L’instruction return permet de sortir d’une méthode sans nécessairement attendre la fin de celle-ci. Cette instruction ne peut donc pas figurer directement dans le main, mais sera très largement utilisée par la suite.

Exercices 1) Ouvrez le fichier Tableau1.java du dossier tableau1 avec WordPad. public class Tableau1 { public static void main(String[] args) { double[] t ; int n = 20 ; t = new double[n] ; for (int i = 0 ; i < n ; i++) { t[i] = i ; } for (int i = 0; i < n ; i++) { System.out.print(t[i] + " * "); } (1) } }

Ajoutez après la ligne (1) une boucle while pour faire afficher les éléments du tableau t tant que ceux-ci sont inférieurs à 12. Compilez et exécutez. 2) Faites exécuter plusieurs fois de suite le programme Tableau2 du dossier tableau2. Ouvrez ensuite le fichier avec WordPad : public class Tableau2 { public static void main(String[] args) { int n=20 ; double[] t = new double[n] ; java.util.Random r = new java.util.Random(); (1) for (int i = 0 ; i < n ; i++) { t[i] = r.nextInt(50) ; (2) } for (int i = 0; i < n ; i++) { System.out.print(t[i] + " * "); } (3) } }

Ce programme fait appel à un générateur de nombres aléatoires appelé r, qui est créé par la ligne (1) :

java.util.Random r = new java.util.Random();

10

r génère successivement 20 nombres entiers tous compris entre 0 et 50 car à la ligne (2) r.nextInt(50) fournit à chaque fois un entier aléatoire compris entre 0 et 50 Ajoutez après la ligne (3) une boucle do … while pour faire afficher le premier élément du tableau tab, puis les éléments suivants tant que ceux-ci sont inférieurs ou égaux au premier élément. Compilez et exécutez.

3. java, langage à objets

Classes et instances Un programme java peut ne contenir qu’une seule classe, comme on l’a vu jusqu’à présent. Cette classe, qui contient alors la méthode main, constitue à elle toute seule toute l’application. Mais java est avant tout un “langage à objets”, ce qui veut dire qu’une classe peut aussi être un moule à partir duquel on peut fabr iquer des objets qu’on appelle des instances. On souhaite créer des « objets » comportant : o un entier n qui représente la taille d’un tableau o un tableau t de n entiers comportant les entiers 1, 2, 3, … n Exemple de deux tels objets :

La classe (encore embryonnaire) correspondant à ces objets est la suivante : class ObjetTableau { // début de la classe int n ; // deux attributs : n entier int[] t ; // et t tableau d’entiers } // fin de la classe

Cette description signifie que tout objet de la classe ObjetTableau, dès qu’il sera créé, comportera automatiquement deux var iables (qu’on appellera des attr ibuts) n et t.

Une classe correspond donc à la description d’un ensemble d’objets ayant une structure de données commune. Les objets créés selon ce modèle sont appelés des instances de la classe.

Pour donner des valeurs aux attributs, donc remplir n et t, on doit ajouter dans la classe ObjetTableau une méthode spécifique appelée constructeur : class ObjetTableau { // début de la classe int n ; // deux attributs : n et t int[] t ; ObjetTableau(int a) { // le constructeur n = a ; // n prend la valeur a t = new int[n] ; // on réserve la place pour t for (int i=0 ; i < n ; i++) { t[i] = i+1 ; // remplissage de t } } // fin du main } // fin de la classe

Langage à Objets : Java

11

Créer des objets de la classe ObjetTableau se fait ailleurs, dans une autre classe qui sert de programme principal : public class ProgObjet { // début de classe public static void main (String args[ ]) { // le main ObjetTableau obj1 = new ObjetTableau(6); ObjetTableau obj2 = new ObjetTableau(3); } // fin du main } // fin de classe

Ce programme crée bien les deux objets en mémoire, mais n’affiche RIEN. o On ajoute donc à la première classe une méthode void affiche() affichant les éléments du tableau t

et une méthode int inferieurs(int p) calculant le nombre d’éléments du tableau t inférieurs à p class ObjetTableau { // début de la classe int n ; // deux attributs : n et t int[] t ; ObjetTableau(int a) { // le constructeur n = a; // n prend la valeur a t = new int[n] ; // on réserve la place pour le tableau t for (int i=0;i<n;i++) { // remplissage du tableau t[i] = i+1 ; } } // fin du constructeur void affiche() { System.out.println("affichage des elements"); for (int i = 0; i < n; i++){ System.out.print(t[i]+" * "); } System.out.println(""); } int inferieurs(int p) { int compteur = 0 ; for (int i = 0; i < n; i++){ if (t[i]<p) compteur++ ; } return compteur ; } } // fin de la classe

o On ajoute à la seconde classe, les instructions demandant aux deux objets créés d’effectuer leurs deux

méthodes : public class ProgObjet { // classe principale public static void main (String args[ ]) { // main ObjetTableau obj1 = new ObjetTableau(6); obj1.affiche(); // affichage de obj1 // on recherche le nb d’elements < 3 System.out.println(obj1.inferieurs(3)) ; // nb d’elements < 3 ObjetTableau obj2 = new ObjetTableau(3); obj2.affiche(); // affichage de obj2 // on recherche le nb d’elements < 4 System.out.println(obj2.inferieurs(4)) ; // nb d’elements < 4 } // fin du main } // fin de classe

Les méthodes affiche et inferieurs ne peuvent être exécutées que par des objets : ce sont des méthodes d’instances. void affiche() affiche les éléments, mais ne calcule rien, d’où son type de valeur de retour : void int inferieurs(int p) calcule le nombre d’éléments de t strictement inférieurs à p o int (valeur de retour) indique que le résultat est un entier (valeur du compteur) o int p est l’argument de la méthode o return permet de renvoyer la valeur du compteur

12

Le fichier comporte finalement deux classes : la classe ObjetTableau et la classe ProgObjet. Il y aura donc deux fichiers compilés. o Il s’agit d’une application, car il y a dans une des classes une méthode appelée main. o La classe principale est celle qui comporte la méthode main ; elle doit impérativement être déclarée public o On l’appelle souvent aussi classe maître de l’application. Le fichier doit porter le nom de cette classe maître, suivi de l’extension .java. Ce sera donc ici ProgObjet.java

Attributs et méthodes d’instances Une classe peut être un moule permettant de construire des objets (ce n’est pas obligatoire). Mais un objet est nécessairement créé à partir d’une classe, à l’aide d’un constructeur de cette classe ; on dit alors que l’objet est une instance de la classe et qu’il est du type de la classe.

Un objet comporte des attr ibuts d’instance et dispose de méthodes d’instance, définis dans la classe. Ainsi, dans la classe ObjetTableau, o n et t sont des attributs d’instance o les méthodes void affiche() et int inferieurs(int p) sont des méthodes d’instance

Attributs et méthodes de classes Une classe peut aussi comporter des attr ibuts de classe et des méthodes de classe. Ils sont signalés par le mot-clé static et existent dès le début de l’application, même si aucun objet de la classe n’a encore été créé. Seule exception : le constructeur est une méthode de classe, même s’il n’est pas précédé de static.

Exemple d’utilisation d’un attribut de classe et d’une méthode de classe pour compter les objets créés : Attribut de classe : static int nbobjets o initialisé au lancement de l’application o modifié dans le constructeur Méthode de classe : static void nombreObjets() o appelée dans le programme principal sur le nom de la classe : ObjetTableau.nombreObjets(); class ObjetTableau { static int nbobjets = 0; // initialisation du compteur int n ; int[] t ; ObjetTableau(int a) { n = a; t = new int[n] ; for (int i=0;i<n;i++) { t[i] = i+1 ; } nbobjets++ ; // incrémentation du compteur } void affiche() { System.out.print("affichage d'un objet :"); for (int i = 0; i < n; i++){ System.out.print(t[i]+" * "); } System.out.println(""); } static void nombreObjets() { // méthode de classe System.out.println("Nombre d'objets : " + nbobjets) ; } }

Langage à Objets : Java

13

public class ProgObjet1 { // début de classe public static void main (String args[ ]) { // le main ObjetTableau.nombreObjets() ; // appel à la méthode de classe ObjetTableau obj1 = new ObjetTableau(6); obj1.affiche(); // affichage de obj1 ObjetTableau.nombreObjets() ; // appel à la méthode de classe ObjetTableau obj2 = new ObjetTableau(10); obj2.affiche(); // affichage de obj2 ObjetTableau.nombreObjets() ; // appel à la méthode de classe } // fin du main } // fin de classe

4. Les paquetages Java

Qu’est-ce qu’un paquetage ? Les paquetages (packages) sont des librairies de classes, de classes d’exceptions et d’inter faces regroupées selon leur fonction. La documentation concernant chaque paquetage est stockée sous forme de pages HTML dans le dossier docs du JDK.

java.lang Le paquetage java.lang est le seul paquetage dont l’emploi ne doit jamais être déclaré. Il comprend notamment la classe Object, la classe System, les classes enveloppantes, la classe Math et la classe Str ing (classe des chaînes de caractères). La classe Object est à l’origine de toutes les classes. Si on ne précise pas de clause d’héritage en définissant une nouvelle classe, celle-ci hérite de Object. La classe System contient des variables et des méthodes du système. Les classes enveloppantes : les variables des types de données primitifs (int, char, double, etc) sont les seuls éléments qui ne sont pas des objets dans Java. Mais on peut, en cas de besoin, les transformer en objets à l’aide de classes enveloppantes suivantes :

int n = 5 ; // n n’est pas un objet Integer obj1 = new Integer(n) ; // obj1 est un objet

double f = 1/3 ; // f n’est pas un objet Double obj2 = new Double(f) ; // obj2 est un objet La classe Math contient les méthodes nécessaires (méthodes de classe) pour les calculs mathématiques. Exemple : double j = -3.145 ; double k = Math.abs(j) ; La classe Str ing contient de très nombreuses méthodes d’instance pour le traitement des chaînes de caractères.

type nature classe enveloppante

boolean true ou false Boolean

char caractère 16 bits Character

byte entier 8 bits signé (petit entier) Byte

short entier 16 bits signé (entier court) Short

int entier 32 bits signé (entier) Integer

long entier 64 bits signé (entier long) Long

float virgule flottante 32 bits (réel simple) Float

double virgule flottante 64 bits (réel double) Double

14

Exercice Compilez le fichier Test1.java du dossier STRING, dont le texte est donné ci-dessous, et faites-le exécuter. Regardez ce que renvoie chaque méthode. public class Test1 { public static void main(String args[]) { String s1 = "Bonjour" ; System.out.println("s1 vaut "+s1+" et est de longueur "+s1.length()); char c = s1.charAt(3) ; System.out.println("La caractere au 3eme indice est : " +c) ; String s2 = s1.toUpperCase(); if (s1.equalsIgnoreCase(s2)) { System.out.println("s1 et s2 sont equivalents"); } String s3=" et bonne journee" ; String s4 = s2.concat(s3) ; System.out.println("s4 vaut : " + s4); String s5 = "bon" ; int pos = s4.indexOf(s5) ; if (pos == -1) System.out.println("s4 ne contient pas s5"); else System.out.println("s4 contient s5 a l’indice "+pos); String s6 = s4.substring(3, 8); System.out.println("entre les indices 3 et 8 de s4 on trouve "+s6); } }

java.util Le paquetage java.util contient des classes utilitaires : Calendar , Gregor ianCalendar , Random… Pour utiliser une partie d’un paquetage autre que java.lang, on utilise le mot-clé impor t : o import java.util.GregorianCalendar ;

on se donne le droit d’utiliser la classe GregorianCalendar (qui permet de créer des objets de type date (jour-mois-année-heure-minute-seconde…)

o import java.util.Random ;

on se donne le droit d’utiliser la classe Random

o import java.util.* ; on se donne le droit d’utiliser toutes les classes du paquetage

Exercice : utilisation d’un tableau de nombres aléatoires Ouvrez le dossier UTILALEATOIRE. Il comporte le fichier UtilAleatoire.java suivant : import java.util.Random ; // déclare que l’on veut utiliser la classe Random class TableauAleatoire { static int max = 100 ; // entier qui donne la valeur maximale des nombres // aléatoires qui seront générés (variable de classe)

int nb ; // variable d’instance : nombre d'éléments du tableau int t[] ; // variable d’instance : un tableau d'entiers

TableauAleatoire(int m) { // le constructeur nb = m ;

t = new int[nb] ; Random r = new Random() ; // crée le générateur de nombres aléatoires for (int i = 0 ; i < nb ; i++) { t[i] = r.nextInt(max) ; // entier aléatoire entre 0 et max } }

Langage à Objets : Java

15

void affiche() { // méthode d'instance réalisant l'affichage du tableau // affiche les réels du tableau t séparés par des espaces

for (int i = 0; i < nb ; i++) { System.out.print(t[i]+ " ") ; } System.out.println(""); // un saut de ligne pour terminer }

} public class UtilAleatoire {

// le programme principal public static void main (String args[ ]) {

TableauAleatoire obj1 = new TableauAleatoire(50) ; // un objet obj1.affiche() ; // appel de affiche() sur l’objet }

}

Ajoutez à la classe TableauAleatoire deux méthodes d’instance int maximum() et int minimum() renvoyant respectivement le plus grand et le plus petit élément du tableau t. Pour tester les méthodes, modifiez la classe UtilAleatoire de la manière suivante : public class UtilAleatoire {

public static void main (String args[ ]) { TableauAleatoire obj1 = new TableauAleatoire(50) ; obj1.affiche() ; System.out.println("Maximum : " + obj1.maximum()) ; System.out.println("Minimum : " + obj1.minimum()) ; }

}

La notion d’héritage On déclare qu’une classe dérive d’une autre classe par : class classe-fille extends classe-mère {

… }

Si une classe B dérive d’une classe A, elle hériteUn objet de la classe fille est donc un objet de la classe mère (éventuellement complété par des champs et des méthodes supplémentaires), mais la réciproque est fausse.

des champs et des méthodes de A.

Toutes les classes héritent de la classe Object. Si on précise pas de clause d’héritage dans la définition d’une classe, par défaut, elle hérite de Object. Les méthodes héritées d’une classe mère A peuvent être redéfinies dans la classe fille B. Cette possibilité de redéfinir les méthodes est appelée le polymorphisme : un objet de type A et un objet de type B sont capables de répondre au même message, mais en faisant appel à des méthodes de contenus différents.

Les interfaces Une interface est une sorte de classe spéciale, dont toutes les méthodes sont déclarées public et abstract (sans code). En fait, une interface propose des services, mais sans donner le code permettant d’exécuter ces services. Une classe qui souhaite utiliser une interface le signale par le mot implements :

class B implements C {…} ; On dit alors qu’elle implémente l’interface. Dans la classe B, on doit alors donner le code de toutes les méthodes de l’interface. Une classe B peut hériter d’une classe A et implémenter

class B extends A implements C, D {…} ; une ou plusieurs interfaces :

class A interface C, D

extends implements

class B Les méthodes des interfaces C et D doivent alors obligatoirement être définies dans la classe B.

16

Les classes d’exceptions Lorsqu’une méthode est exécutée, il peut se produire des erreurs. On dit alors qu’une exception est levée. Une exception est un objet, instance d’une des nombreuses sous-classes de la classe Exception. Chaque méthode qui risque de provoquer une ou des erreur(s) le signale par le mot throws suivi de la nature des erreurs susceptibles de se produire. Lorsqu’on a besoin d’utiliser une méthode risquant de provoquer des erreurs, on englobe l’appel à cette méthode dans un bloc try (pour capturer l’erreur) et on précise ce qu’on fera en cas d’erreur dans une clause catch (pour traiter l’erreur). Exemple : try {

fichier.read() ; }

catch (IOException) { System.out.println(" erreur de lecture ") ; return ; }

Les différentes classes d’erreurs possibles sont spécifiées dans chaque paquetage.

5. Le paquetage graphique java.awt Les paquetages java.awt et javax.swing fournissent toutes les classes permettant de bâtir des interfaces graphiques. La classe Component (ou JComponent) est à l’origine de la plupart des classes graphiques. En italiques, les classes abstraites (qui n’autorisent pas la création d’instances). Les classes Component et JComponent sont ainsi des classes abstraites ; leur rôle rôle est de proposer des méthodes qui seront héritées par tous les objets des sous-classes. Dans la parabole, ce qui est extérieur au paquetage java.awt, mais dérive d’une classe de java.awt ou javax.swing. En flèches pointillées, les implémentations d’interfaces.

Button

Canvas

Checkbox

Choice Panel Applet

Component ContainerDialog FileDialog

Label WindowFrame

List

ScrollbarTextArea

TextComponentTextField

MenuBarMenuComponent

MenuItem

BorderLayout

CardLayout

FlowLayoutLayoutManager

GridBagConstraints

GridBagLayout

GridLayout

Langage à Objets : Java

17

Principe de construction d’une interface graphique Les composants (fenêtres, boutons, cases à cocher, etc) sont insérés dans un objet dérivant de la classe Container , qui groupe les composants et les dispose pour l’affichage. Les objets de type Panel (ou JPanel) permettent de disposer les composants. Les objets de type Window (ou JWindow) sont des fenêtres simples. Les objets de type Frame (ou JFrame) servent à définir des fenêtres avec scrollbar, titre, etc, tandis que les objets de type Dialog (ou JDialog) définissent les fenêtres de dialogue avec l’utilisateur. Chaque container possède un LayoutManager (gestionnaire de placement), qui définit comment sont placés les objets qu’il contient. LayoutManager est en fait une interface qu’implémentent plusieurs classes, dont : o BorderLayout, qui répartit les objets au Nord, Sud, Est, Ouest et Centre (c’est l’option par défaut pour un

Frame) o FlowLayout qui les répartit de gauche à droite puis passe à la ligne suivante (c’est l’option par défaut pour

un Panel) o GridLayout qui les répartit dans un tableau dont toutes les cases ont la même taille.

Exemples

Appli1.java

import java.awt.* ; class Appli1 { public static void main(String arg[]) { Frame w = new Frame("Exemple") ; w.add("North", new Label("Un")) ; w.add("Center", new Label("Deux")) ; w.add("South", new Label("Trois")) ; w.show() ; w.pack() ; } }

BorderLayout par défaut :

Appli2.java import java.awt.* ; class Appli2 { public static void main(String arg[]) { Frame w = new Frame("Exemple") ; w.setLayout(new FlowLayout()) ; w.add(new Label("Un")) ; w.add(new Label("Deux")) ; w.add( new Label("Trois")) ; w.show() ; w.pack() ;

} }

FlowLayout choisi :

Appli3.java import java.awt.* ; class Appli3 { public static void main(String arg[]) { Frame w = new Frame("Exemple") ; w.setLayout(new GridLayout(2,2)) ; w.add(new Label("Un")) ; w.add(new Label("Deux")) ; w.add( new Label("Trois")) ; w.add( new Label("Quatre")) ; w.show() ; w.pack() ;

} }

GridLayout choisi :

18

Exemple de construction d’interface graphique Un objet de la classe Panel est un Container puisque la classe Panel dérive de la classe Container. Il peut donc lui-même comporter des composants, dont d’autres Panel. Chaque Panel gère alors ses propres composants avec le LayoutManager qui lui est propre. On va construire l’interface graphique suivante :

correspondant au schéma :

import java.awt.* ; class Fenetre extends Frame { Panel p1, p2, p3, p31, p32 ;

TextArea txt ; Button bouton1, bouton2, bouton3 ; CheckboxGroup cbg ; Checkbox chb1, chb2, chb3 ;

List selection1, selection2 ; Fenetre() {

setLayout(new FlowLayout()) ;

// construction du Panel p1 p1 = new Panel() ; p1.setLayout(new GridLayout(4,1)) ; p1.add(new Label("Jour")) ; selection1 = new List(3) ; selection1.addItem("lundi") ; selection1.addItem("mardi") ; selection1.addItem("mercredi") ; selection1.addItem("jeudi") ; selection1.addItem("vendredi") ; selection1.addItem("samedi") ; selection1.addItem("dimanche") ; p1.add(selection1) ; p1.add(new Label("Horaire")) ; selection2 = new List(3) ; selection2.addItem("9 h - 12 h") ; selection2.addItem("12 h - 15 h") ; selection2.addItem("15 h - 18 h") ; selection2.addItem("18 h - 21 h") ; p1.add(selection2) ; add(p1) ;

Langage à Objets : Java

19

// construction du Panel p2 p2 = new Panel() ; p2.setLayout(new GridLayout(4,1)) ; p2.add(new Label("Localisation")) ; cbg = new CheckboxGroup(); chb1 = new Checkbox("Paris", cbg, true); p2.add(chb1) ; chb2 = new Checkbox("Lyon", cbg, false); p2.add(chb2) ; chb3 = new Checkbox("Marseille", cbg, false); p2.add(chb3) ; add(p2) ; // construction du Panel p3 p3 = new Panel() ; p3.setLayout(new BorderLayout()) ; p31 = new Panel(); bouton1 = new Button("Valider") ; p31.add(bouton1) ; bouton2 = new Button("Désélectionner") ; p31.add(bouton2) ; p3.add("North", p31) ; txt = new TextArea(5,30) ; p3.add("Center",txt) ; p32 = new Panel() ; bouton3 = new Button("Quitter") ; p32.add(bouton3) ; p3.add("South", p32) ; add(p3) ; } // fin du constructeur

} // fin de la classe Fenetre public class UtilFenetre { // classe utilisateur

public static void main(String args[]) { Fenetre f = new Fenetre() ; f.pack() ; f.show() ; }

}

Les deux classes constituent le fichier UtilFenetre.java construisant l’interface graphique souhaitée. Il n’est pas (encore) possible de fermer l’application car les événements ne sont pas encore gérés. On ferme donc l’application par CTRL C dans la fenêtre d’invite de commandes.

Exercices 1) Créez un dossier appelé QCM. Ecrivez un programme CreeQCM.java (comportant une classe principale CreeQCM et une classe QCM) générant l’interface graphique suivante :

Cette interface graphique comporte : o un Label pour le texte « La capitale du Sri Lanka est : » o un CheckboxGroup appelé cbg pour associer logiquement les quatre Checkbox o les quatre Checkbox chb1, chb2, chb3 et chb4 correspondant aux propositions o un Button appelé bouton pour valider o un TextField appelé txt pour l’affichage du résultat ces objets étant rangés dans des Panel pour obtenir une présentation correcte de l’interface graphique. Compilez et exécutez ensuite le programme. Sortez par CTRL C dans la fenêtre d’Invite de commandes.

20

2) Créez un dossier appelé Liste. Ecrivez un programme CreeListe.java (comportant une classe principale CreeListe et une classe Liste) générant l’interface graphique suivante :

La classe Liste comporte un générateur de nombre aléatoire r de la classe Random et deux entiers a et b générés aléatoirement entre 1 et 100. L’interface graphique qu’elle créé comporte : o un Label pour le texte « Le produit de (valeur de a) par (valeur de b) vaut : » o un objet List appelé propositions pour afficher les propositions (calculées) a+b, ab, a+2b et 2ab o un Button appelé bouton pour valider o un TextField appelé txt pour l’affichage du résultat ces objets étant rangés dans des Panel pour obtenir une présentation correcte de l’interface graphique. Compilez et exécutez ensuite le programme. 3) Créez un dossier appelé Trou. Ecrivez un programme CreeTrou.java (comportant une classe principale CreeTrou et une classe Trou) générant l’interface graphique suivante :

Cette interface graphique comporte : o un Label pour le texte « ‘Le Cid’ est une pièce d’un célèbre auteur français. Lequel ? » o un TextField appelé reponse pour entrer la réponse o un Button appelé bouton pour valider o un TextField appelé txt pour l’affichage du résultat ces objets étant rangés dans des Panel pour obtenir une présentation correcte de l’interface graphique. Compilez et exécutez ensuite le programme.

6. La gestion des événements

Principe L’interface graphique délègue la gestion des événements à des classes extérieures. Les traitements consécutifs aux événements sont ainsi totalement séparés de l’interface graphique elle-même.

Modèle MVC (METHODE - VUE - CONTROLEUR)

Interface graphique = VUE (instance d’une classe)

Prise de décision = CONTROLEUR (instance d’une autre classe)

Action = METHODE (instance d’une troisième classe)

Langage à Objets : Java

21

Mise en œuvre en Java Une interface graphique (VUE) contient des objets. On attache un listener (surveillant) aux objets graphiques que l’on souhaite particulièrement surveiller (Button, List, Window, Canvas …) Listener étant une famille d’inter faces, le listener sera nécessairement un objet d’une classe implémentant une de ces interfaces. On appellera cette classe la classe Adaptateur , car elle sera chargée d’adapter le comportement de l’interface aux actions effectuées par l’utilisateur. L’objet de la classe Adaptateur, étant devenu un listener , sera automatiquement averti des événements (event) qui se produisent sur les objets surveillés. Il décidera alors des actions à entreprendre en fonction de la demande de l’utilisateur, et donnera l’ordre à un exécuteur d’effectuer ces actions. Enfin l’exécuteur sera un objet d’une classe que l’on appellera classe Delegue ; il exécutera les actions demandées par le listener et interagira avec l’interface graphique pour en modifier l’apparence.

Illustration par deux exemples

Clic sur un bouton contenu dans l’interface graphique

Clic sur le bouton de fermeture de la fenêtre

22

Programmation La VUE est l’interface graphique. C’est une instance d’une classe graphique. Le CONTROLEUR est une instance d’une classe que l’on appellera Adaptateur, implémentant les Listeners nécessaires. L’Adaptateur décide comment « adapter » l’apparence de l’interface graphique aux actions demandées par l’utilisateur. La METHODE est une instance d’une classe que l’on appellera Delegue, contenant toutes les actions à réaliser sur l’interface graphique. Le CONTROLEUR « délègue » à la METHODE la responsabilité des actions à entreprendre. 1) Dans le constructeur de l’interface graphique, on déclare un attribut de nom delegue (de type Delegue) puis on demande à la classe Delegue la création d’un objet Delegue en lui envoyant l’adresse de l’interface graphique :

Delegue delegue ; delegue = new Delegue(this) ; // this = adresse de l’interface graphique

L’adresse du délégué ainsi créé est donc stockée dans l’attribut delegue de l’interface graphique. De son côté, le délégué stocke dans un de ses attributs (appelé ici fen) l’adresse de l’interface graphique pour pouvoir ultérieurement agir sur elle :

Analogie avec le courrier : Nous écrivons à un destinataire que nous venons de découvrir (à une adresse que nous gardons en mémoire) et nous lui envoyons notre propre adresse (this) pour qu’il puisse lui-même la stocker et nous répondre plus tard. 2) On définit la classe Adaptateur qui “écoute” les événements et décide des actions à faire accomplir par le délégué. Pour cela, la classe Adaptateur implémente une ou plusieurs interfaces de la famille des Listener. Exemple : pour surveiller les éléments sur un bouton et sur une fenêtre, il faut écrire :

class Adaptateur implements WindowListener, ActionListener { ...

} puis on définit obligatoirement dans la classe Adaptateur toutes les méthodes des deux interfaces WindowListener et ActionListener. 3) On déclare dans le constructeur de l’interface graphique un attribut appelé adapt (de type Adaptateur) et on demande ensuite à la classe Adaptateur de créer un objet de la classe Adaptateur ; on lui envoie l’adresse du délégué, puisque c’est au délégué que l’adaptateur s’adressera :

Adaptateur adapt ; adapt = new Adaptateur(delegue) ;

Langage à Objets : Java

23

Penser encore à l’analogie avec le courrier : nous écrivons à un second destinataire (l’Adaptateur adapt), mais nous lui demandons de répondre ultérieurement au premier destinataire (le delegue), dont il n’a pas a priori l’adresse. Il faut donc lui passer cette adresse, pour qu’il puisse la stocker. L’interface graphique stocke l’adresse de l’adaptateur dans l’attribut adapt, tandis que l’adaptateur stocke celle du délégué dans un attribut delegue :

4) Dans le constructeur de l’interface graphique, on “enregistre” l’Adaptateur adapt sur les composants qu’il doit surveiller. Les méthodes d’enregistrement des adaptateurs dépendent des classes de ces composants. Exemple : si bouton1 est un objet de la classe Button, et si adapt doit surveiller bouton1, on écrira :

bouton1.addActionListener(adapt) ;

5) On écrit enfin dans la classe Delegue les méthodes nécessaires pour que le délégué puisse effectuer les actions nécessaires sur l’interface graphique.

Application à l’interface graphique précédente import java.awt.* ; import ... class Fenetre extends Frame { // la VUE Panel p1, p2, p3, p31, p32 ; TextArea txt ; Button bouton1, bouton2, bouton3 ; CheckboxGroup cbg ; Checkbox chb1, chb2, chb3 ; List selection1, selection2 ; // ajout de deux attributs : Delegue delegue ; Adaptateur adapt ;

24

Fenetre() { … // construction des Panel p1, p2 et p3 ... // ajout : création du délégué et de l’adaptateur delegue = ... adapt = ... // ajout : enregistrement de l’adaptateur comme listener addWindowListener... bouton1.addActionListener... bouton2.addActionListener... bouton3.addActionListener... }

}

// la classe utilisateur (classe principale) public class UtilFenetre { public static void main(String args[]) { Fenetre f = new Fenetre() ; f.pack() ; f.show() ; }

} class Adaptateur implements ActionListener, WindowListener { // le CONTROLEUR Delegue delegue ; Adaptateur(Delegue d) { delegue = d ;

} // une méthode indispensable comme ActionListener public void actionPerformed(ActionEvent e) { Object src = ... String param = ... if (param == "Quitter") delegue.quitter() ; else if (param == "Désélectionner") delegue.annulle() ; else delegue.affichetexte() ; } // sept méthodes indispensables comme WindowListener public void windowClosing(WindowEvent e) { delegue.quitter() ; } public void windowClosed(WindowEvent e) {} public void windowIconified(WindowEvent e) {} public void windowDeiconified(WindowEvent e) {} public void windowActivated(WindowEvent e) {} public void windowDeactivated(WindowEvent e) {} public void windowOpened(WindowEvent e) {} } class Delegue { // la METHODE Fenetre fen ; Delegue(Fenetre f) { fen = f ;

} public void quitter() { ...

} public void annulle() { fen.selection1.deselect... fen.selection2.deselect... fen.chb1.setState... fen.chb2.setState... fen.chb3.setState... fen.txt.setText... } public void affichetexte() { String res = "Vous avez choisi le " + ... res=res + "\ndans la tranche horaire " + ... res=res + "\nà " + ... fen.txt.setText... } }

Langage à Objets : Java

25

Exercices Gérez les événements dans chacun des trois fichiers CreeQCM.java, CreeListe.java et CreeTrou.java de telle sorte que la fenêtre se ferme lors d’un clic sur le bouton de fermeture et que le message affiché soit « Exact » si la réponse est bonne et « Erreur : la réponse est … » sinon.

A noter ! Pour récupérer les réponses de l’utilisateur : o dans un groupe de Checkbox :

String reponse = fen.cbg.getSelectedCheckbox().getLabel() ; donne le nom de la ville choisie sous forme de chaîne de caractères

o dans un objet de type List : String reponse = fen.propositions.getSelectedItem() ; donne la valeur choisie sous forme de chaîne de caractères

o dans une zone de texte de type TextField ou TextArea : String reponse = fen.reponse.getText() ; donne ce qui a été tapé sous forme de chaîne de caractères.

Si le contenu de la réponse correspond à un nombre, il faut convertir la chaîne de caractères en nombre. On convertit une chaîne de caractères reponse en : o un nombre entier par : int rep = new Integer(reponse).intValue() ; o un nombre réel de type float par : float rep = new Float(reponse).floatValue() ; o un nombre réel de type double par : double rep = new Double(reponse).doubleValue() ; Inversement, si on doit afficher un nombre dans une fenêtre graphique, il faut d’abord le convertir en une chaîne de caractères. On convertit : o un entier nb en chaîne resultat par : String resultat = new Integer(nb).toString() ; o un float nb en chaîne resultat par : String resultat = new Float(nb).toString() ; o un double nb en chaîne resultat par : String resultat = new Double(nb).toString() ;

7. Les applets Java

Qu’est-ce qu’une applet ? Une applet est une application portable, insérée dans une page HTML et chargée par un navigateur en même temps que la page HTML. Exécutée par l’interpréteur java du navigateur , l’applet permet de délocaliser certains traitements (calculs, animations graphiques, vérification de la validité d’un formulaire, etc) chez le client. Du point de vue informatique, une applet est une classe Java héritant de la classe Applet et gérant seule son apparence pour répondre aux demandes de l’utilisateur. Exemples : o Applet Dessin : faire exécuter la page Dessin.html par le navigateur. o Applet Geometr ique : faire exécuter la page Geometrique.html par le navigateur.

Différences entre applet et application o Une application réside sur le disque dur , tandis qu’une applet, chargée à travers le réseau, reste en

mémoire sans être stockée sur le disque dur de la machine qui l’exécute. o Une application est lancée une seule fois, tandis qu’une applet est initialisée et démarrée, puis redémarrée à

chaque fois que l’utilisateur recharge la page HTML dans laquelle elle se trouve. o Une applet a moins de droits qu’une application classique : elle ne peut ni lire ni écrire de fichier sur le

disque du client, ni lancer de programme ; elle ne peut communiquer qu’avec le serveur dont elle est issue.

26

Insertion d’une applet dans une page HTML <APPLET en gras ce qui est obligatoire

CODEBASE=codebase_URL URL où on cherche le fichier .java CODE="nomclasse.class" nom du fichier de pseudo-code ALT="texte_de_remplacement" texte si navigateur non compatible NAME="nom_instance" nom de l’applet dans la page html WIDTH=pixels largeur puis hauteur de la HEIGHT=pixels > zone d’affichage de l’applet <PARAM NAME=nom_param1 VALUE="valeur1"> paramètres éventuels <PARAM NAME=nom_param2 VALUE="valeur2"> </APPLET> La balise OBJECT, plus récente, a été créée pour permettre l’insertion d’éléments de différents types dans une page HTML sans être obligé de définir une balise pour chaque type de composant : contrôle ActiveX, applets, images, animations Flash etc. Elle n’est pas encore acceptée par tous les navigateurs. <OBJECT

classid="java:nomclasse.class" en gras ce qui est obligatoire codetype="application/java" name=="nom_instance" width=pixels height=pixels>

</OBJECT> Exemple: <applet code="Geometrique.class" width="600" height="400"> </applet> est équivalent (pour les navigateurs qui l’acceptent) à : <object classid="java:Geometrique.class" codetype="application/java" width="600" height="400"> </object>

Méthodes spécifiques à une applet La classe, publique, dérive de la classe Applet. Elle ne comporte pas de main, mais des méthodes spécifiques : o le constructeur de la classe est facultatif ; o une méthode init() réalise l’initialisation de l’applet ; o une méthode star t() lance l’applet au démarrage et à chaque fois que l’Applet a été stoppée (au

rechargement de la page HTML, par exemple) ; o une méthode stop() arrête temporairement l’applet (lors d’un changement de page, par exemple) ; o une méthode destroy() détruit l’applet (lors de la fermeture du navigateur) ; o une méthode paint(Graphics g) dessine en permanence l’applet sur l’écran à l’aide d’un contexte graphique

g fourni.

Gestion d’une applet Lorsqu’un navigateur a fini de charger une page HTML contenant une applet, il lance l’interpréteur java qui appelle la méthode init() de l’applet. Cette méthode initialise l’applet et charge les images, les sons et les données dont l’applet a besoin. Pour lancer et dessiner l’applet, l’interpréteur appelle ensuite les méthodes star t() et paint() de l’applet. L’applet assume ensuite avec ses propres méthodes la gestion de sa zone d’affichage. Elle peut demander à être redessinée par un appel à la méthode repaint().

Programmer une applet Lorsqu’on créé des applets, les méthodes qu’il faut le plus couramment redéfinir sont donc : o init() pour initialiser l’applet o paint(Graphics g) si on utilise des éléments graphiques Les autres méthodes héritées de la classe Applet n’ont généralement pas à être redéfinies. Si l’on veut que l’utilisateur puisse interagir avec l’applet, il faut en outre définir les classes Delegue et Adaptateur gérant les événements.

Langage à Objets : Java

27

Exécuter une applet Une applet ne s’exécute pas par un appel direct à l’interpréteur java, contrairement à une application, mais via

une page HTML chargée par un navigateur contenant l’interpréteur java Il y a deux manières d’exécuter des applets : o faire appel à un visualiseur (l’appletViewer) simulant le navigateur et à qui on donne le nom de la page

HTML contenant l’applet que l’on veut visualiser. appletViewer page.html La page HTML n’est pas visible, seule l’applet est visualisée. o faire appel à un navigateur à qui on donne le nom de la page HTML contenant l’applet.

Les images dans les applets La classe Applet du paquetage java.applet contient une méthode appelée getImage qui permet à l’applet de charger en mémoire (mais pas d’afficher) une image provenant du serveur. Cette méthode renvoie un objet de la classe Image (classe du paquetage java.awt.image). On écrira donc, par exemple,

Image im = getImage(getDocumentBase(), "vnus.gif") ; getDocumentBase() (également de la classe Applet) permet de trouver, sur le serveur, le répertoire où se trouve la page HTML dans laquelle est insérée l’applet. De manière analogue, getCodeBase() permet de trouver, sur le serveur, le répertoire où se trouve le pseudo-code de l’applet.

La classe Graphics (du paquetage java.awt) s’occupe de l’apparence graphique des applications et des applets. Sa méthode drawImage permet l’affichage d’une image en un point. On écrira donc, si g est un contexte graphique,

Image im = getImage(getDocumentBase(), "vnus.gif") ; g.drawImage(im, 20, 20, this) ;

pour afficher l’image im à partir du point (20,20). Le 4e argument de drawImage doit être un ImageObserver (interface de java.awt.image). Comme la classe Component (dont dérive Applet) implémente cette interface, l’applet (this) est un ImageObserver. Exemple d’applet chargeant une image : import java.awt.* ; import java.applet.* ; import java.awt.image.* ; public class AppletImage extends Applet {

Image im ; public void init() {

im = getImage(getDocumentBase(), "vnus.gif") ; }

public void paint(Graphics g) { g.drawImage(im, 20, 20, this) ; }

}

Page appletimage.html correspondante : <HTML> <HEAD> <TITLE> Applet</TITLE> </HEAD> <BODY>

<APPLET CODE="AppletImage.class" WIDTH=300 HEIGHT=300> </APPLET>

</BODY> </HTML>

28

Exercices Le dossier CHARGEIMAGES comporte les fichiers ChargeImages.java et ExempleChargeImages.html ainsi que les 19 fichiers images im1.jpg, im2.jpg, …, im19.jpg. Compilez le fichier ChargeImages.java puis faites charger la page ExempleChargeImages.html par le navigateur. Les boutons « Suivante » et « Précédente » sont pour l’instant inactifs. Le but de l’exercice est de les rendre actifs. Ouvrez le fichier ChargeImages.java avec WordPad : import java.awt.* ; import java.applet.* ; import java.awt.image.* ; import java.awt.event.* ; public class ChargeImages extends Applet { Panel p ; Image image ; Button suivant, precedent ; int rang ; ... public void init() { setLayout(new BorderLayout()) ; rang = 1 ; p = new Panel() ; suivant = new Button("Suivante") ; p.add(suivant) ; precedent = new Button("Précédente") ; p.add(precedent) ; add("South", p) ; ... } public void paint(Graphics g) { image = getImage(getDocumentBase(), "im"+rang+".JPG") ; g.drawImage(image, 10, 10, this) ; } } class Delegue { ChargeImages ci ; Delegue(ChargeImages c) { ci = c ; } public void avancer() { ... ci.repaint() ; } public void reculer() { ... ci.repaint() ; } } class Adaptateur implements ActionListener { Delegue delegue ; public Adaptateur(Delegue d) { delegue = d ; } public void actionPerformed(ActionEvent e) { Object src = e.getSource(); String param = ((Button)src).getLabel(); if (param == "Suivante") delegue.avancer() ; else delegue.reculer() ; } }

Complétez les lignes manquantes pour associer un adaptateur aux boutons « Suivante » et « Précédente » et faire en sorte que les clics sur ces boutons soient actifs.

Langage à Objets : Java

29

Tranformation d’une application en applet

Conditions On peut transformer une application en applet à condition : o de ne pas avoir besoin de lire ou écrire sur le disque dur du client (ce qui est interdit à une applet) o de ne pas avoir de traitement complexe à effectuer sur le serveur, mais uniquement y lire ou y écrire des

données

Modifications à effectuer o importer le paquetage java.applet o faire dériver la classe de l’interface graphique de la classe Applet (au lieu de la classe Frame) o supprimer la classe principale de l’application o la classe de l’interface graphique étant devenue la classe principale, la déclarer public, et renommer son

constructeur en public void init() o renommer le fichier en lui donnant comme nom le nom de la nouvelle classe principale o modifier la classe Adaptateur pour qu'elle n'implémente plus l'interface WindowListener (une applet ne

pouvant pas fermer le navigateur) o modifier la classe Delegue en conséquence o compiler et tester.

Exercices Transformez les trois applications CreeQCM, CreeListe et CreeTrou en trois applets QCM, Liste et Trou, chacune étant intégrée dans la page HTML correspondante : qcm.html, liste.html et trou.html.

qcm.html liste.html trou.html

Paramètres provenant de la page HTML Une page HTML peut passer des paramètres à une applet. Si la page HTML contient les lignes :

<applet code= "truc.class" …> <param name="langage" value="java">

</applet>

alors on peut récupérer dans l’applet la valeur de la variable langage par : String langage=getParameter("langage") ;

Exercices 1a) Modifiez la page trou.html en mettant le texte de la question ainsi que la réponse dans des balises <param> : <applet code="Trou.class" width=350 height=140>

<param name="question" value="Le Cid est une pi&egrave;ce d'un auteur français. Lequel ?">

<param name="reponse" value="Corneille"> </applet> 1b) Modifiez le fichier Trou.java de telle sorte que l’applet récupère, à partir de la page HTML, la question et la réponse.

30

1c) Complétez ensuite la page HTML en ajoutant un deuxième appel à la même applet : <applet code="Trou.class" width=350 height=140>

<param name="question" value="Le Cid est une pi&egrave;ce d'un auteur français. Lequel ?">

<param name="reponse" value="Corneille"> </applet> <p>Autre question : </p> <applet code="Trou.class" width=350 height=140> <param name="question" value="Quel est l'auteur de Ph&egrave;dre ?"> <param name="reponse" value="Racine"> </applet> En visualisant la page trou.html vous obtenez les deux questions l’une en-dessous de l’autre, sans recompilation de l’applet. L’applet peut ainsi être utilisée pour des questions à trou variées, soit dans la même page HTML soit dans des pages différentes (voir illustration en bas, figure 1). 2a) Modifiez la page qcm.html en lui ajoutant des balises <param> : <applet code="QCM.class" width=270 height=180> <param name="question" value="La capitale du Sri Lanka est "> <param name="rep1" value="Kandy"> <param name="rep2" value="Colombo"> <param name="rep3" value="Chandernagor"> <param name="rep4" value="Pondichéry"> <param name="sol" value="Colombo"> </applet> 2b) Modifiez ensuite le fichier QCM.java de telle sorte que l’applet récupère, à partir de la page qcm.html, la question, les quatre propositions et la solution. 2c) Ajoutez ensuite dans la page HTML une seconde question et les propositions correspondantes (remarquez que l’on peut modifier, si nécessaire, les dimensions de l’applet lorsque le texte de la question est plus long) : <applet code="QCM.class" width=270 height=180> <param name="question" value="La capitale du Sri Lanka est "> <param name="rep1" value="Kandy"> <param name="rep2" value="Colombo"> <param name="rep3" value="Chandernagor"> <param name="rep4" value="Pondichéry"> <param name="sol" value="Colombo">

</applet> <p>Autre question : </p> <applet code="QCM.class" width=300 height=180>

<param name="question" value="Quelle ville a le plus grand nombre d'habitants ?"> <param name="rep1" value="Rio de Janeiro"> <param name="rep2" value="Montevideo"> <param name="rep3" value="Brasilia"> <param name="rep4" value="La Paz"> <param name="sol" value="Rio de Janeiro">

</applet> En visualisant la page qcm.html vous obtenez les deux questions. L’applet peut dès lors être utilisée pour des QCM variés, soit dans la même page HTML soit dans des pages différentes (voir ci-dessous, figure 2).

Figure 1

Figure 2

Langage à Objets : Java

31

Inconvénient de la lecture des balises param : elles sont visibles dans le code de la page HTML. Donc la question et les réponses sont accessibles à l’utilisateur. Pour éviter cela, on va lire les fichiers contenant les questions et les réponses sur le serveur.

Lecture d’un fichier par une applet o Une applet ne peut lire ou écrire un fichier que sur le disque dur du serveur dont elle est issue. o Les classes nécessaires à ce qu’on appelle les « entrées/sorties » appartiennent au paquetage java.io, celles

concernant les connexions réseau au paquetage java.net. Il faut donc importer ces paquetages.

Exemple Dans le dossier COMMUNICATION, figure une applet qui lit un fichier texte sur le serveur et l’affiche ligne à ligne à chaque fois que l’on clique sur un bouton “ Suite ”. Le nom du fichier figure dans une balise param. La première ligne du fichier à lire doit indiquer le nombre de lignes de texte du fichier. Exemple de fichier à lire : texte.txt 4 les sanglots longs des violons de l’automne bercent mon coeur d’une langueur monotone

Page ExempleCommunication.html : <HTML> <HEAD><TITLE> Applet</TITLE></HEAD> <BODY> <center><H2>Communication</H2></center> <center><APPLET CODE="Communication.class" WIDTH=400 HEIGHT=200> <param name="fichier" value="texte.txt"> </APPLET></center> </BODY> </HTML>

Fichier Communication.java : import java.awt.* ; import java.applet.* ; import java.awt.event.* ; import java.io.* ; import java.net.* ; public class Communication extends Applet { String [] chaine = new String[15] ; int nblignes, k ; TextArea texte ; Button b ; Delegue delegue ; Adaptateur adapt ; public void init() { delegue = new Delegue(this); adapt = new Adaptateur(delegue); setLayout(new BorderLayout()) ; texte = new TextArea(); add("North", texte) ; chargement() ; k = 0 ; b = new Button("Suite") ; b.addActionListener(adapt); add("South", b) ; } public void chargement(){ URL url ; InputStream stream ; BufferedReader fichier ;

32

try { url = new URL(getDocumentBase(), getParameter("fichier")) ; stream = url.openStream() ; fichier =new BufferedReader(new InputStreamReader(stream)); } catch (IOException e) { texte.setText("erreur de fichier") ; return ; } try { nblignes = Integer.parseInt(fichier.readLine()) ; for (int i = 0 ; i < nblignes ; i++) chaine[i] = fichier.readLine() ; } catch (IOException e) { texte.setText("erreur de transfert") ; return ; } } } class Delegue { Communication com ; Delegue(Communication c) { com = c ; } public void traiter() { if (com.k < com.nblignes) { com.texte.setText(com.texte.getText() + "\n" + com.chaine[com.k]) ; // ou com.texte.append("\n" + com.chaine[com.k]) ; com.k++ ; } } } class Adaptateur implements ActionListener { Delegue delegue ; public Adaptateur(Delegue d) { delegue = d ; } public void actionPerformed(ActionEvent e) { delegue.traiter() ; } }

Modification Dans la page ExempleCommunication.html, remplacez le nom du fichier « texte.txt » par « java.txt » et faites recharger la page HTML par le navigateur. L’affichage correspond maintenant au nouveau fichier, sans avoir eu à recompiler l’applet.

Exercices 1a) Créez avec WordPad les fichiers qcm1.txt et qcm2.txt ci-dessous. Enregistrez-les dans le dossier QCM.

qcm1.txt qcm2.txt 6 La capitale du Sri Lanka est Kandy Colombo Chandernagor Pondichéry Colombo

6 Quelle ville a le plus grand nombre d'habitants ? Rio de Janeiro Montevideo Brasilia La Paz Rio de Janeiro

1b) Modifiez la page qcm.html de la manière suivante : <applet code="QCM.class" width=270 height=180> <param name="fichier" value="qcm1.txt"> </applet> <p>Autre question : </p> <applet code="QCM.class" width=300 height=180> <param name="fichier" value="qcm2.txt"> </applet> 1c) Faites en sorte que chaque applet QCM lise la question et les réponses proposées dans le fichier dont le nom figure en balise <param> (utilisez la méthode chargement() de l’applet Communication.java telle quelle).

Langage à Objets : Java

33

2a) Créez les deux fichiers trou1.txt et trou2.txt ci-dessous. Enregistrez-les dans le dossier Trou.

trou1.txt 2 Le Cid est une pi&egrave;ce d'un auteur français. Lequel ? Corneille

trou2.txt 2 Quel est l'auteur de Ph&egrave;dre ? Racine 2b) Modifiez la page trou.html de la manière suivante : <applet code="Trou.class" width=350 height=140> <param name="fichier" value="trou1.txt"> </applet> <p>Autre question : </p> <applet code="Trou.class" width=350 height=140> <param name="fichier" value="trou2.txt"> </applet> 2c) Faites en sorte que chaque applet Trou lise la question et la bonne réponse dans le fichier dont le nom figure en balise <param>.

Communication entre applets d’une même page

Principe La méthode getAppletContext() permet à une applet de savoir quelles sont les autres applets qui se trouvent dans la même page HTML qu’elle. Soit l’extrait de page HTML suivant : <APPLET CODE="Applet1.class" NAME="applet1" WIDTH=100 HEIGHT=200> </APPLET> <APPLET CODE="Applet2.class" NAME="applet2" WIDTH=100 HEIGHT=300> </APPLET>

Si l’on souhaite que l’applet2 communique avec l’applet1, on écrit, dans une méthode de la classe Applet2 : Applet ap=getAppletContext().getApplet("applet1") ; // ap est effectivement l’applet1, mais considérée (pour l’instant) // comme un objet de la classe mère Applet Applet1 applet1 = (Applet1) ap; // opérateur de cast, convertissant concrètement ap en un objet // de la classe Applet1 que l’on nomme applet1 applet1.methode(arguments) ; // l’applet2 demande à l’applet1 d’exécuter une de ses méthodes ; // les arguments éventuels de la méthode permettent de // transmettre des valeurs de l’applet2 à l’applet1

Exemple

34

Page commApplets.html

<html> <head><title>Applets</title></head> <body>

<center><H3>Communication entre deux applets</H3> On choisit un &eacute;crivain dans la premi&egrave;re applet<br> et on clique sur OK<br> <applet code="Applet1.class" name="applet1" width=120 height=60> </applet><br> et une liste d'oeuvres est affich&eacute;e dans l'autre applet :<br><br> <applet code="Applet2.class" name="applet2" width=200 height=80> </applet></center>

</body> </html>

Applet1.java

import java.awt.* ; import java.applet.* ; import java.awt.event.* ; public class Applet1 extends Applet { protected Panel p ; protected Choice c1 ; protected Button bouton ; protected Delegue1 d1 ; protected Adaptateur1 adapt1 ; public void init() { d1 = new Delegue1(this) ; setLayout(new BorderLayout()) ; p = new Panel() ; c1 = new Choice() ; c1.add("Victor Hugo"); c1.add("Emile Zola"); c1.add("André Malraux"); p.add(c1) ; bouton = new Button("OK") ; p.add(bouton) ; add("Center", p) ; adapt1 = new Adaptateur1(d1) ; bouton.addActionListener(adapt1) ; } } class Delegue1 { protected Applet1 ap1 ; Delegue1(Applet1 a) { ap1 = a ; } void envoie() { Applet applet=ap1.getAppletContext().getApplet("applet2") ; Applet2 applet2 = (Applet2)applet ; applet2.recois(ap1.c1.getSelectedItem()) ; } } class Adaptateur1 implements ActionListener { protected Delegue1 delegue1 ; Adaptateur1(Delegue1 dd) { delegue1 = dd ; } public void actionPerformed(ActionEvent e) { delegue1.envoie() ; } }

Langage à Objets : Java

35

Applet2.java

import java.awt.* ; import java.applet.* ; public class Applet2 extends Applet { protected List l2 ; public void init() { setLayout(new BorderLayout()) ; l2 = new List(5) ; add("Center", l2) ; } void recois(String s) { l2.removeAll() ; if (s.equalsIgnoreCase("Victor Hugo")) { l2.add("Les misérables") ; l2.add("Les contemplations") ; l2.add("La légende des siècles") ; l2.add("Les orientales") ; l2.add("Les châtiments") ; } else if (s.equalsIgnoreCase("Emile Zola")) { l2.add("Pot-bouille") ; l2.add("Germinal") ; l2.add("La débâcle") ; l2.add("Le ventre de Paris") ; l2.add("L'argent") ; } else if (s.equalsIgnoreCase("André Malraux")) { l2.add("La condition humaine") ; l2.add("La voie royale") ; l2.add("Les chênes qu'on abat") ; l2.add("La métamorphose des Dieux") ; l2.add("Les voix du silence") ; } } }

Exercice Dans le dossier interets figure une page Interets.html appelant deux applets. o L’applet Donnees permet à un utilisateur d’entrer un montant initial et un nombre d’années ; le taux

d’intérêt est donné en balise <param> dans Interets.html. o L’applet Resultat doit permettre afficher le capital acquis à la fin du placement. Complétez la méthode calcule() de l’applet Resultat afin qu’elle calcule et fasse afficher le résultat attendu :

36

Exercice de révision On donne le fichier questions.txt qui comporte : - en première ligne, un nombre de questions (14) - ensuite des couples de lignes, chaque couple comportant la ligne d’énoncé d’une question et la ligne contenant la réponse correcte (voir ci-dessous). questions.txt 14 Le chat miaule Le chien aboie L'éléphant barrit Le corbeau croasse Le bélier blatère Le cerf brame Le cheval hennit Le chacal jappe La grenouille coasse Le lièvre vagit Le serpent siffle Le tigre feule Le loup hurle La vache beugle

Construisez une applet nommée Exercice.java que vous insérerez dans une page exercice.html afin d’obtenir le résultat ci-dessous :

A noter : 1) L’applet fera appel à une méthode void chargement() lisant le fichier questions.txt et remplissant deux tableaux de chaînes de caractères : l’un pour les questions, l’autre pour les réponses. 2) L’applet affichera ensuite dans une zone de texte de type TextField une question tirée au hasard parmi les questions existantes et proposera dans un objet de type Choice la liste de toutes réponses. 3) Après appui sur le bouton « Valider », l’analyse de la réponse s’affichera dans une seconde zone de texte de type TextField, avec la correction en cas de réponse incorrecte.

Exemples :

Langage à Objets : Java

37

38

Annexes

Noms des variables Le nom d’une variable commence obligatoirement par une lettre. Il peut être constitué de lettres, de chiffres ou du caractère souligné _ et peut contenir un nombre quelconque de caractères (se limiter pour la commodité à une taille raisonnable). Les mots clés du langage ne doivent pas être utilisés comme nom de variable. Ce sont les mots : abstract assert boolean break byte case catch char class const continue default do double else extends false final finally float for goto if implements import instanceof int interface long native new null package private protected public return short static strictfp super switch synchronized this throw throws transient true try void volatile while Il y a une distinction entre minuscules et majuscules (java est toujours sensible à la CASSE). Par convention les noms de variable sont orthographiés en lettres minuscules sauf la première lettre de chaque mot si le nom de la variable en comporte plusieurs : nomDeFamille par exemple.

Portée des variables La portée d’une variable est la portion de code dans laquelle on peut manipuler cette variable. Elle est fonction de l’emplacement où est située la déclaration de la variable. La déclaration d’une variable peut être faite dans le bloc de code d’une classe, le bloc de code d’une fonction ou un bloc de code à l’intérieur d’une fonction. Seul le code du bloc où est déclarée la variable peut l’utiliser. Il ne peut pas y avoir deux variables portant le même nom avec la même portée. On peut cependant déclarer une variable interne à une fonction ou un paramètre d’une fonction ayant le même nom qu’une variable déclarée au niveau de la classe. La variable déclarée au niveau de la classe est dans ce cas masquée par la variable interne à la fonction.

Niveaux d’accès des variables (protection des variables) Le niveau d’accès d’une variable détermine quelle portion de code a le droit de lire et de modifier la variable. Un ensemble de mots clés permettent de contrôler le niveau d’accès. Ils s’utilisent lors de la déclaration de la variable et doivent être placés devant le type de la variable. Ils sont uniquement utilisables pour la déclaration d’une variable à l’intérieur d’une classe. Leur utilisation à l’intérieur d’une fonction est interdite. o private : la variable est utilisable uniquement par le code de la classe où elle est définie. o protected : la variable est utilisable dans la classe où elle est définie, dans les sous-classes de cette classe et

dans les classes qui font partie du même paquetage. o public : la variable est accessible à partir de n’importe quelle classe indépendamment du paquetage. o aucun modificateur : la variable est accessible à partir de toutes les classes faisant partie du même

paquetage.