20/11/00 _________________________________________________________ _________________________________________________________ Le langage JAVA 1.1 : le résumé auteur : Véronique Gaildrat _________________________________________________________ _________________________________________________________ Cours Java 1.1 1 20/11/00 Table des matières 1.Le langage............................................................................................................................... 4 1.1 Syntaxe....................................................................................................................................... 4 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 Expressions...................................................................................................................................... 4 Instructions ...................................................................................................................................... 5 Variables ......................................................................................................................................... 6 Types ............................................................................................................................................... 6 Tableaux.......................................................................................................................................... 7 1.2 Classes ....................................................................................................................................... 7 1.2.1 1.2.2 1.2.3 1.2.4 Définition de classes ........................................................................................................................ 7 Variables de classes ......................................................................................................................... 8 Constantes ( mot clef final ) ............................................................................................................. 8 Interrogation sur les classes.............................................................................................................. 8 1.3 Instances..................................................................................................................................... 8 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 Variables d'instances........................................................................................................................ 8 Création........................................................................................................................................... 9 This ................................................................................................................................................. 9 Super ............................................................................................................................................. 10 Clones............................................................................................................................................ 10 Comparaison : equals..................................................................................................................... 11 instanceOf...................................................................................................................................... 11 1.4 Contrôle de la visibilité des variables et des méthodes ................................................................ 11 1.5 Méthodes .................................................................................................................................. 12 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 Déclaration de méthodes ................................................................................................................ 12 Mode de transmission des paramètres ............................................................................................ 12 Surcharge des méthodes et Constructeurs....................................................................................... 13 Destructeurs [option]...................................................................................................................... 15 Appel des méthodes ....................................................................................................................... 15 Méthodes de classe (mot clef static)................................................................................................ 16 Main.............................................................................................................................................. 17 1.6 Exemple.................................................................................................................................... 17 2.Héritage (mot clef extends).................................................................................................... 18 2.1 Héritage simple ......................................................................................................................... 19 2.2 Conversion de types .................................................................................................................. 19 2.3 Conversion d'objets (typage dynamique) .................................................................................... 19 2.4 Polymorphisme - Redéfinition.................................................................................................... 20 3.Méthodes et classes abstraites................................................................................................ 20 4.Exceptions............................................................................................................................. 21 4.1 Hiérarchie de classes exception.................................................................................................. 21 4.2 Créer une nouvelle classe exception ........................................................................................... 21 4.3 Récupérer une exception............................................................................................................ 21 4.4 Debugger .................................................................................................................................. 22 4.5 Lever une exception .................................................................................................................. 22 Cours Java 1.1 2 20/11/00 4.6 La clause throws ....................................................................................................................... 22 4.7 La clause finally........................................................................................................................ 23 5.Input / Output ....................................................................................................................... 23 5.1 Affichage à l'écran .................................................................................................................... 23 5.2 Lecture au clavier...................................................................................................................... 24 5.3 Entrées/Sorties dans un fichier................................................................................................... 25 6.Packages ............................................................................................................................... 28 7.Interfaces (mot clef implements) ............................................................................................ 30 8.AWT et gestion des événements ............................................................................................ 30 8.1.1 Identification du bouton cliqué....................................................................................................... 31 8.2 Version simple .......................................................................................................................... 31 8.3 Version complète (plus complexe) ............................................................................................. 32 9.Threads ................................................................................................................................. 35 10. Exemple ............................................................................................................................ 36 Cours Java 1.1 3 20/11/00 1. Le langage 1.1 Syntaxe 1.1.1 Expressions Commentaires // fin de ligne commentée /* commentaire borné aux extrémités */ /** pour javadoc */ pour générer de la doc de façon automatique Constantes : -4 // cte entière de type int 4L // entier long de valeur 4 0777 // cte octale 0XFF // hexadécimal 10e45 ou .36E-2 ou 5.62 // cte virgule flottante double 2.56f // cte float Booléen : true ou false Caractères : 'a' // caractère a \n // <RC, LF> \r // <RC> \t // tab \f // saut de page \b // back \\ // anti slash \' // guillemet simple \" // guillemet double \d // octal \x // hexadécimal \u // unicode (symboles codés) Constantes chaînes : "ceci est une chaîne" "" // chaîne vide "ceci est un chaîne avec \" guillemets \" à l'intérieur" \u2122 // ™ (trade mark) Opérateurs et expressions : + * / // int / int -> int % // modulo == // ATTENTION syntaxe du test d'égalité C like !!!! != // différent < <= > >= && // ET logique || // OU logique ! // NON logique ^ // XOR bit à bit ~ // NOT bit à bit << // décalage à gauche bit à bit >> // décalage à droite bit à bit >>> // décalage à droite avec remplissage avec des 0 bit à bit & // ET bit à bit | // OU bit à bit Cours Java 1.1 4 20/11/00 new 1.1.2 Instructions création d'une nouvelle instance de classe Toute instruction est toujours terminée par un ---> ; // affectation i = 1; // déclaration int i; // déclaration avec affectation d'une valeur initiale à la variable int i = 1; // initialisation d'une variable d'instance m.engineStart = True; // affichage à l'écran d'un message composé de chaînes de carac et de valeurs numériques System.out.println ("texte entre les guillemets " + entier1 + "...." + string1 + flottant1 + ....); // bloc d'instructions { // dans les structures de contrôle, on peut trouver une instruction ... // ou un bloc d'instructions } // instruction conditionnelle if ( cond ) instruction // ou { bloc d'instructions } else instruction; // ou { bloc d'instructions } // opérateur conditionnel test ? true_result : false_result; // test true => exécution de true_result, false_result sinon int smaller = x < y ? x : y; // branchement conditionnel switch (variable) // type de base autorisé : byte, char, short, int, long { case v1 : { ... // accolades si bloc d'instructions } break; case v2 : instruction; break; default : default_result; } // boucle for for (cond. initiales; cond d'arrêt; expression devant faire évoluer vers la cond d'arrêt) instruction; // ou { bloc d'instructions } // boucle while while (cond) instruction; // ou { bloc d'instructions } do Cours Java 1.1 5 20/11/00 { ...; } while (cond); Les sorties de blocs peuvent être forcées par l'instruction break. Il y a la possibilité de faire des boucles étiquetées. exterieur: for ( cond ) { while ( x < 50 ) { ... if ( cond ) { break exterieur; } } } L'instruction continue permet de redémarrer la boucle à la prochaine itération. Cela permet d'éviter certains tests mais il vaut mieux éviter de l'utiliser si on ne maîtrise pas ... 1.1.3 Variables Les variables locales sont déclarées et utilisées dans les blocs. Les valeurs des variables de classe s'appliquent à toutes les instances de la classe (et à la classe elle même); Les variables d'instance sont les attributs de la classe et permettent de connaître l'état d'une instance donnée. On ne trouve pas de variables globales. // déclaration de variables type nom de var = init; type n1 = v1, n2 = v2, n3 = v3; // toute variable locale doit être initialisée avant d'être utilisée. Les instances de classe sont initialisées à null à la déclaration. Les variables d'instance et de classe sont initialisées par défaut à la création de l'instance : num -> 0 carac -> '\0' bool -> false Convention de noms de variables pour les mots combinés : le premier en minuscule, les autres en majuscule (un nom de classe est toujours majuscule). Exemple : Button theButton 1.1.4 Types 8 types de données de base : byte (octet) short (2 octets) int (4 octets) long (8 octets) Toute classe est un type : Cours Java 1.1 float double char boolean (4 octets) (8 octets) (2 octets non signés) (true, false) 6 20/11/00 String Font 1.1.5 Tableaux lastName; basicFont; Les tableaux sont typés. Il faut déclarer une variable pour stocker l'adresse du tableau : Point hits []; // <=> Point [] hits; !! Il faut ensuite créer une nouvelle instance tableau et affecter sa référence à la variable. ATTENTION de la même façon qu'en C les indices pour un tableau de 10 éléments vont de 0 à 9 !! les tableaux sont des tableaux d'instances, il faut donc créer chaque élément du tableau indépendamment 1.1.5.1 Création d'instances de tableaux // 10 références nulles vers une chaîne (et non une chaîne de 10 carac!) String names [] = new String [10]; Point hits [2] = new Point { {10, 20}, {11, 21} }; String riz [] = {"rond", "long", "parfumé"}; // initialisé par les données 1.1.5.2 Accès à un élément hits [0].x --> fournit la valeur 10 hits [1].y --> fournit la valeur 21 ATTENTION vérification de dépassement de capacité names [10] = "toto" => erreur de compilation ou d'exécution si l'indice est évalué à l'exec int len = names.length; // len recevra la valeur 10 1.1.5.3 Multidimensionnels int coords [][] = new int [4][4]; ... coords [0][0] = 15; coords [0][1] = 12; 1.2 Classes Toute classe hérite de façon implicite de la classe Object qui est donc à la racine de toute arborescence de classes. Classe Attributs <=> Variables d’instances -> stockées dans l’instance Variables de classe -> stockées dans la classe Comportement <=> méthodes définies dans la classe Méthodes d’instances appelées Méthodes Méthodes de classe qui agissent sur la classe 1.2.1 Définition de classes Cours Java 1.1 7 20/11/00 - simple : class MyClassName { ...; } - héritage : class MyClassName extends ClasseParente { ...; } - référence à une interface : class MyClassName implements nomInterface1, nI2, ... { ...; } 1.2.2 Variables de classes Pour qu'une variable déclarée dans la classe soit considérée comme une variable de classe, il faut placer le mot clef static dans sa déclaration : class Famille { static String nom = "Durand"; String prénom; int âge; ... } Durand est fixé pour toutes les instances de famille. Prénom et âge sont propres à chaque instance. Famille dad = new Famille (); System.out.println (" nom : " + dad.nom); // donne le même résultat que System.out.println (" nom : " + Famille.nom); 1.2.3 Constantes ( mot clef final ) Les constantes sont déclarées dans les classes ou en local : final float pi = 3.141592f; final int maxsize = 4000000; 1.2.4 Interrogation sur les classes - getClass ( ) Permet de déterminer la classe d'une instance (utile en cas de typage dynamique). Class classe = obj.getClass ( ); - getName ( ) Retourne le nom de la classe String name = obj.getClass ( ).getName ( ); 1.3 Instances 1.3.1 Variables d'instances Cours Java 1.1 8 20/11/00 Les variables d'instances sont référencées au moyen de la notation pointée : Object myObject; ... myObject.var = val; // var est une variable d'instance de la classe Object myObject.otherObject.otherVar = true; | | variable | instance instance class Vélo extends PersonPoweredVehicle { String bikeType; // var d'instance : vtt, route ou city ... } 1.3.2 Création La création d'une instance se fait au travers d'un new => allocation + constructeur. L'allocation est dynamique et un garbage collector se charge de récupérer la mémoire allouée et qui n'est plus référencée. Seules les instances de type String n'ont pas besoin d'un new. String s = "une chaîne qq"; Mais String s = new String (); est possible et générera une chaîne vide. Pour les autres classes : Random r = new Random (); Motorcycle m2 = new Motorcycle (); Quand on fait appel à un constructeur sans paramètres, une instance de base est créée avec des valeurs par défaut . Quand le constructeur attend des arguments, ils déterminent les valeurs initiales des (toutes ou certaines) variables d'instances. ATTENTION : certaines classes interdisent la création d'objets sans arguments. Ex : import java.util.Date; class createDates { public static void main (String args [] ) // static => méthode de classe { Date d1, d2, d3; d1 = new Date (); // sans paramètres System.out.println (" Date 1 " + d1 ); d2 = new Date (71, 7, 1, 7, 30); System.out.println (" Date 2 " + d2 ); d3 = new Date ("April 3 1993 3:24 PM"); System.out.println (" Date 3 " + d3 ); } } 1.3.3 This Cours Java 1.1 9 20/11/00 Le mot clef this référence l'instance courante : t = this.x; <=> t = x x variable de la classe de l'instance courante this.myMethod (this); <=> myMethod (this) méthode de la classe appliquée à l'instance courante return this; retourne l'instance courante 1.3.4 Super Le mot clef super référence la classe parente de la classe courante (précisé au §2) : Class Auto extends Vehicule { public void imprimer () { ... super.imprimer (); // fait appel à la méthode imprimer // de la classe Véhicule 1.3.5 Clones b An mois d jour Day b = new Day (1959, 6, 16); Day d = b; ... d.advance (100); // modifie d ET b Ici, d et b référencent la même instance (le même objet) Day d = (Day) b.clone ( ); // clone retourne un objet de classe Object => conversion explicite ... d.advance (100); // b inchangé clone est une méthode "protected" de Object => seul une classe ayant accès à la classe Day peut cloner une instance de la classe Day. nom : Bond Agent 007 date naiss : jour : nom : berurier mois : New 007 date naiss : ATTENTION ceci effectue un clonage au premier niveau. Pour réaliser l'équivalent d'un DeepClone de Eiffel (clonage récursif) il faut implanter l'interface cloneable, redéfinir la méthode clone avec accès "public". Pour cloner une classe il faut : Cours Java 1.1 10 20/11/00 la déclarer cloneable : public class XXX implements Cloneable { // toute donnée de base sera clonée par l'appel de super.clone() // toute donnée qui est une instance de classe doit être clonée en appelant sa méthode clone propre // qui doit donc être implantée // Vector possède de base une méthode clone Vector donnees = new ....; ...... protected Object clone() throws CloneNotSupportedException { XXX copie = (XXX)super.clone(); copie.donnees = (Vector)donnees.clone(); return copie; } } 1.3.6 Comparaison : equals La comparaison simple d'instances de classes non prédéfinies, à l'aide de la méthode equals, est une comparaison de références qui a rarement un sens. Pour comparer le contenu de deux instances dont les classes ne sont pas prédéfinies, il faut redéfinir la méthode equals dans la classe dont on veut comparer les instances. Comme la méthode equals est définie dans la classe Object, elle est connue par toute classe. 1.3.7 instanceOf instanceOf s'utilise comme une expression booléenne : "foo" instanceOf String --> true Point pt = new Point (10, 10); pt instanceOf String --> false 1.4 Contrôle de la visibilité des variables et des méthodes public : pas de restriction d'accès, une variable ou méthode est visible à toute classe Variable RW pour toute classe package : c'est le niveau de protection par défaut. La visibilité est limitée aux classes du package courant. Variable RW pour les classes du package protected : Visible par toutes classes du package courant ET toutes les sous-classes qu'elles soient ou non du paquetage. Variable RW pour les classes du package ET toute sous-classe Cours Java 1.1 11 20/11/00 private : interne à la classe, pour encapsuler les données => méthodes d'accès publique pour retourner la valeur d'une variable private. ATTENTION une méthode et une variable d'instance peuvent avoir le même nom, seules les () les distinguent. final : le modificateur final - pour une classe, interdit d'en hériter - pour une variable, la rend constante - pour une méthode, interdit de la redéfinir constantes : public static final int aConstantInt = 123; // const de classe public final String aConstantStrinf = " une chaîne de carac "; // const d'instance ATTENTION les méthodes private sont déjà final 1.5 Méthodes 1.5.1 Déclaration de méthodes contrôle_de_visibilité returnType { ... } Si returnType est un tableau public int [] moyenneEtudiants { ... } nomMéthode ( [type arg1, ... , type argn]) ( groupe notes[]) 1.5.2 Mode de transmission des paramètres Les types données de base sont transmis par valeur. Par contre les instances passées en paramètres sont transmises par référence et sont donc susceptibles d'être modifiées si leur contrôle de visibilité le permet. Exemple : public class PassByReference { public int OneToZero ( int arg [ ] ) // remplace par 0 les 1 trouvés dans un tableau { int count = 0; for ( int i = 0; i < arg.length; i++ ) { if ( arg[i] == 1 ) { count = count + 1; arg[i] = 0; } } return count; } // la méthode principale main ( ) teste la méthode OneToZero ( ) public static void main ( String arg [] ) Cours Java 1.1 12 20/11/00 { int arr [] = {1, 3, 4, 5, 1, 1, 7 }; PassByReference test = new PassByReference ( ); int numOnes; System.out.print ("Valeurs du tableau : [ " ); for ( int i = 0; i < arr.length; i++ ) { System.out.print ( arr [i] + " "); } System.out.println ("]"); numOnes = test.OneToZero ( arr ); System.out.print ("Nombre de 1 = " + numOnes ); System.out.print ("Nouvelles valeurs du tableau : [ " ); for ( int i = 0; i < arr.length; i++ ) { System.out.print ( arr [i] + " "); } System.out.println ("]"); } } Résultat de l'exécution : Valeurs du tableau : [ 1 3 4 5 1 1 7 ] Nombre de 1 = 3 Nouvelles valeurs du tableau : [ 0 3 4 5 0 0 7 ] 1.5.3 Surcharge des méthodes et Constructeurs Il est possible de surcharger des méthodes, soit dans une même classe, soit dans une classe héritière qui surchargera alors des méthodes de ses classes parentes. La surcharge est effective dès lors qu'il y a modification des arguments de la méthode surchargée. La modification du type retourné par la méthode n'est pas significative et non testée par le compilateur. Exemple de surcharge : import java.awt.Point; // utilisation de la classe Point qui se trouve dans le Package awt class MyRect { Point p1, p2; void buildRect ( int x1, int y1, int x2, int y2 ) { this.p1.x = x1; this.p1.y = y1; this.p2.x = x2; this.p2.y = y2; } void buildRect ( Point topLeft, Point bottomRight ) { p1 = topLeft; // affectation de références p2 = bottomRight; Cours Java 1.1 13 20/11/00 } public static void main (String args [] ) { MyRect rect = new MyRect ( ); rect.buildRect (20, 30, 40, 50 ); rect.buildRect (new Point (10,10), new Point (20, 20) ); } } On peut également surcharger les constructeurs qui allouent la place nécessaire aux variables d'instance et qui vont également les initialiser, soit avec les valeurs par défaut, soit avec les valeurs passées en paramètre. ATTENTION les constructeurs sont des méthodes particulières qui portent toujours le nom de la classe, sont des procédures (pas de return) et ne précisent pas de contrôle de visibilité. Class Person { String name; int âge; On doit au minimum créer un constructeur sans paramètres si on hérite d'une classe dont on doit appeler le constructeur à la création d'une instance. Person ([paramètres]) { super ([paramètres]); // en supposant que Person hérite d'une classe } Person (String s, int a ) { name = s; âge = a; } Person (String s ) { name = s; // l'âge est initialisé par défaut à 0 } Public static void main (String args [] ) { Person p1, p2, p3; p1 = new Person ("Laura", 20 ); p2 = new Person ("Laurie"); p3 = new Person ( ); } Mais lorsqu'un constructeur d'une classe est appelé, celui de la classe parente doit l'être aussi et ainsi de suite => ceci afin d'entraîner l'initialisation de toutes les parties héritées de la classe. Exemple : class NamedPoint extends Point { String name; NamedPoint ( int x, int y, String n) { name = n; // this.name = n s'il faut lever une ambiguïté super (x, y); // appelle le constructeur de la classe Point } } import java.awt.Point; class MyRect2 Cours Java 1.1 14 20/11/00 { int x1 = 0; int x2 = 0; int y1 = 0; int y2 = 0; MyRect2 ( int x1, int y1, int x2, int y2 ) { this.x1 = x1; this.x2 = x2; this.y1 = y1; this.y2 = y2; } MyRect2 ( Point topLeft, Point bottomRight ) { x1 = topLeft.x; y1 = topLeft.y; x2 = bottomRight.x; y2 = bottomRight.y; } MyRect2 ( Point topLeft, int w, int h ) { x1 = topLeft.x; y1 = topLeft.y; x2 = x1 + w; y2 = y1 + h; } void printRect ( ) { System.out.print ( "MyRect : <", + x1 + ", " + y1 ); System.out.println ( ", " + x2 + ", " + y2 + ">" ); } public static void main ( String args [] ) { MyRect2 rect; System.out.println ( " Appel de MyRect2 avec les coord -> 25, 25, 50, 50 : "); rect = new MyRect2 ( 25, 25, 50, 50 ); rect.printRect ( ); ... test des autres appels de constructeurs } } 1.5.4 Destructeurs [option] protected void finalize ( ) { ... } Toutes les libérations sont insérées dans le corps de finalize. Cette méthode est appelée par JAVA quand une instance n'est plus référencée. Ceci sert à optimiser la destruction d'un objet en simplifiant le travail du garbage collector. 1.5.5 Appel des méthodes Une méthode déclarée dans une classe s'applique à une instance de cette classe. Cours Java 1.1 15 20/11/00 La méthode methode1 (déclarée dans la classe Object dont myObject est une instance) peut être invoquée par l'instruction : myObject.methode1 (arg1, arg2, ... , argn); ATTENTION les ( ) sont obligatoires dans le cas où la méthode n'a pas d'arguments. Si la méthode invoquée renvoie une instance de classe, on peut y appliquer une méthode : myObject.getClass( ).getName( ); méthode méthode qui renvoie une instance de classe instance de classe class TestString { public static void main ( String args [] ) { String str = "Mieux vaut tard que jamais."; System.out.println ( "La chaîne est : " + str ); System.out.println ( "Longueur de cette chaîne : " + str.length ( ) ); System.out.println ( "Le caractère en position 5 : " + str.charAt (5) ); System.out.println ("La sous-chaîne 11 à 18 : " + str.substring (11, 18) ); System.out.println ("L'index du caractère d : " + str.indexOf ( 'd' ) ); System.out.println ("L'index du début de la sous-chaîne \"tard\":" + str.indexOf ("tard") ); System.out.println ("La chaîne en majuscules : " + str.toUpperCase ( ) ); } } 1.5.6 Méthodes de classe (mot clef static) Ces méthodes s'appliquent à la classe entière et non aux instances. Elles sont donc utilisables même sans instances en écrivant : NomDeLaClasse.methodeAExecuter ([arg, ... arg]); Exemple : la classe Math qui se trouve dans le Package java.lang. Il n'existe pas d'instance de la classe Math qui ne contient que des méthodes appliquées à des valeurs numériques ou des constantes. float f = Math.sin ( x ); // sin est une méthode de classe et x une valeur float root = Math.sqrt (453.0); int max = Math.max (x, y); ATTENTION les affectations entre instances concernent des affectations de références. On ne peut pas accéder dans une méthode de classe (static) à une variable d'instance (non static). Syntaxe de déclaration des méthodes de classes : public static ty pe méthode ([args]){...} type retourné par la méthode indique que c'est une méthode de classe indique que la méthode est disponible pour les clients Exemple de classe qui compte ses instances : Cours Java 1.1 16 20/11/00 public class InstanceCounter { private static int instanceCount = 0; // var de classe private static int instanceCount ( ) { // méthode d'accès à la variable de classe return instanceCount; } private static void incrementCount ( ) { instanceCount = instanceCount + 1; } InstanceCouter ( ) // constructeur { InstanceCounter.incrementCount ( ); // incrémente le compteur à la création } // finalize à décrémente } Les descendants ont accès à instanceCounter, les instances (clients) sont comptées. 1.5.7 Main public static void { ... } main ( String arg [] ) arguments sous forme de tableau de chaînes de carac nom obligatoire de la procédure principale procédure => ne retourne rien méthode de la classe principale accessible pour tous arg permet de récupérer les arguments en ligne de commande : java nomProgramme nomFichier 2 rouge arg[0] arg[1] arg[2] java nomProgramme "nomFichier 2 rouge" arg[0] => trois arguments => un argument Il faut traiter les arguments pour récupérer les valeurs réelles à partir des chaînes de caractères. Ex : Integer.parseInt ( arg[i] ); 1.6 Exemple class Motorcycle { String make; String color; boolean engineState; // true ou false void startEngine () { if (engineState == true) System.out.println (" déjà démarré "); else { engineState = true; System.out.println (" démarrage OK "); } } void showAtts () { System.out.println ("affichage du véhicule " + make + color "); Cours Java 1.1 17 20/11/00 if (engineState == true) System.out.println (" moteur tourne "); else System.out.println (" moteur arrêté "); } } La compilation se fait à l'aide de la commande suivante : javac Motorcycle.java Il est nécessaire d'avoir une méthode main () pour toute application, sinon on aura l'erreur suivante: class Motorcycle : void main (String argv []) is not defined. Aussi on va rajouter la méthode main dans la classe Motorcycle : public static void main (String argv [] ) { // création d'un nouvel objet de la classe Motorcycle et // stockage de sa référence dans la variable m Motorcycle m = new Motorcycle (); // new = constructeur m.make = "yamaha 500"; m.color = "yellow"; // initialisation des variables d'instances System.out.println (" appel de showAtts "); m.showAtts (); System.out.println (" démarrage du moteur "); m.starEngine (); System.out.println (" appel de showAtts "); m.showAtts (); System.out.println (" démarrage du moteur "); m.starEngine (); // affichage de l'état de m // changement d'état // réaffichage de l'état de m // redémarrage => message } 2. Héritage (mot clef extends) Hiérarchie de classes : a b Super classe de b (classe parente, ancêt re de b) Sous classe de a (héritière, descendante) Les sous classes héritent de toutes les méthodes et variables de leurs super classes. Une classe héritière b "est" un a dans le cas d'un héritage de classification sinon, c'est un héritage de construction (cf TD). La classe Object se trouve à la hiérarchie des classes JAVA. Toutes les classes en héritent. C'est la classe la plus générale. Généralement, plus une classe est basse dans la hiérarchie, plus elle est spécialisée. Cours Java 1.1 18 20/11/00 Si une classe est réellement nouvelle et n'hérite pas d'un comportement au travers d'une autre classe, elle va hériter directement (implicitement) de la classe Object et sera ainsi intégrée dans la hiérarchie des classes JAVA (ex. La classe Motorcycle). Dans ce cas l'héritage n'est pas spécifié. Toute modification de classe dans une hiérarchie est répercutée dans toutes les classes héritières. La création de classe est justifiée pour : - regrouper toutes les informations communes dans une classe parente - minimiser les modif. à apporter lors de chaque héritage par rapport a la classe parente. Objet Ancetre de toute classe Marque Couleur Mode de propulsion Véhicule V à moteur V sans moteur Cy lindrée 2 roues Moto Scooter 4 roues Mob Voiture Vélo Sulky Bus Le "new" attribue un emplacement pour chaque variable définie dans la classe courante et toutes ses classes parentes. L'instance à accès à toutes les méthodes de la hiérarchie. La méthode à exécuter est choisie dynamiquement dans la hiérarchie au moment de l'appel. Si deux méthodes dans la hiérarchie ont la même signature (même profil), JAVA exécute la première trouvée en partant de la classe même en en remontant dans les classes parentes => !! On peut définir dans une sous classe une méthode avec la même signature que celle d'une classe parente sans conflit (redefine automatique /= Eiffel). 2.1 Héritage simple Dans JAVA seul l'héritage simple est possible. Le concept d'Interface permet de pallier les inconvénients dus à l'héritage simple en permettant de préciser le comportement d'une classe là où l'héritage lui a conféré sa structure. 2.2 Conversion de types La conversion de int -> long est implicite (rien à préciser) par contre la conversion de long -> int doit être explicite => if ( z < (int) (x/y) ) { ...} 2.3 Conversion d'objets (typage dynamique) Cours Java 1.1 19 20/11/00 A B A B C D aA; bB; aA = bB; // implicite bB = (B) aA; // à expliciter if ( aA instanceOf B) {bB = (B) aA;} Classe instance Pour transformer un type de base en classe, il faut utiliser les classes correspondantes aux types de base. Par exemple la classe Integer correspond au type de base int et peut s'utiliser ainsi : Integer int Objet = new Integer (35); L'initialisation retourne une référence à une zone mémoire allouée correspondant à un Integer qui sera affectée à l'instance intObjet de la classe Integer. Dans l'autre sens on peut écrire : int entier = intObjet.intValue ( ); // retourne la valeur 35 qui est affectée à entier int count = Integer.parseInt ( "42", 10 ); // renvoie la chaîne transformée en décimal 2.4 Polymorphisme - Redéfinition Une classe héritière déclarant une méthode de même nom qu'une classe parente a deux possibilités: - il y a modification des arguments de la méthode et c'est une surcharge au sens ADA, - il n'y a pas modification des arguments et c'est une redéfinition au sens Objet. Le polymorphisme a lieu quand des classes héritières d'une classe parente redéfinissent une méthode de la classe parente. Si on désire appeler la méthode de la classe parente dans la méthode redéfinie de la classe héritière, il faut placer devant le mot clef super : void myMethod ( type a, type b ) { ... super.myMethod ( a, b ); // exécutera la méthode de la classe parente ... } Dans le cas des constructeurs (qui portent le nom de la classe), ils sont hérités mais ne peuvent être redéfinis. 3. Méthodes et classes abstraites Une classe abstraite ne peut pas être instanciée. Ex : public abstract class X // classe abstraite { int varInt; public abstract int methodeAbstraite ([args] ); // doit être implantée par un descendant public void methodeNormale ([args] ) // déjà définie, peut être redéfinie { ...; } } Cours Java 1.1 20 20/11/00 public class Y extends X { public int methodeAbstraite ([args] ) { ... } } 4. Exceptions La notion de programmation par contrat n'existe pas et doit être implantée avec les moyens disponibles, notamment les exceptions. 4.1 Hiérarchie de classes exception Les exceptions sont toutes dérivées de la classe Throwable : Throwable internal error Exception /= des exceptions car on ne peut pas les lever IOException Runtime Exception null pt access out of bounds access bad cast .... Classification des types d'erreurs Toute classe exception dérivée de Throwable supporte un constructeur par défaut (sans paramètres) et un constructeur avec un message de type String en paramètre. 4.2 Créer une nouvelle classe exception class MyEx extends IOException // ou toute autre classe dérivée d'Exception { public MyEx ( ) { ... } public MyEx (arg1 a1, arg2 a2, ...) { ... } } if (cond) { throw new MyEx ( ); } 4.3 Récupérer une exception Cours Java 1.1 21 20/11/00 try { code à exécuter susceptible de lever une exception } catch (TypeException nomException) { traitement de l'exception } catch (AutreTypeException nomException) // pour tester une autre exception { traitement } 4.4 Debugger try { ... } catch (Throwable t ) { t.printStackTrace ( ); // permet d'afficher l'état de la pile d'exécution throw t; // pour répercuter l'erreur } 4.5 Lever une exception Il y a 4 façons de lever une exception : - volontairement - par appel d'une méthode qui en lève une - programming error - erreur interne JAVA On ne lève pas soi-même une run time error (erreur d'exécution). Une méthode qui est une redéfinition d'une méthode parente ne peut pas lever plus d'exceptions que sa méthode parente. Pour lever une exception : IOException ioe = new IOException ( ); ... throw ioe; // cela suffit car elle est déclarée et crée avant throw new MyEx ( ); // pas crée avant : il faut le faire "sur place" 4.6 La clause throws Toute méthode qui est susceptible de lever une exception elle même ou par appel d'une méthode susceptible d'en lever une doit : - soit gérer l'exception dans son code par l'emploi des clauses (try catch), - soit indiquer dans son entête qu'elle est susceptible de transmettre une ou plusieurs exceptions à l'appelant : public String readLine ( ) throws IOException, AutreException, ... { ... } Pour ne pas traiter une exception levée : Cours Java 1.1 22 20/11/00 • Une application appelle une méthode susceptible de transmettre une exception (methodeB appelle methodeA () Throws TypeExceptionQuelconque). • Pour ne pas traiter cette exception, methodeB doit également préciser dans son entête : Throws TypeExceptionQuelconque. • Ceci doit être effectué par toutes les méthodes appelantes et ce en remontant jusqu'au Main. Le traitement explicite de l'exception est OBLIGATOIRE pour les IOException à traitement explicite, mais implicite pour les Runtime ERROR. 4.7 La clause finally Exemple : Graphics g = image.getGraphics ( ); try { code sur g } catch (IOException e) { done = true; // par exemple } finally { g.dispose ( ); // libération du graphic context } Que le code soit ou non exécuté, le code associé à la clause finally sera exécuté. Ici le graphic context sera libéré quelles que soient les circonstances. Code try pas d'exception exception finally géré par catch pas géré par un catch suite d'exec du bloc code du catch finally throw une exception dans la partie catch pas de throw finally finally renvoie du throw à l'appelant suite d'exec du bloc renvoie du throw à l'appelant 5. Input / Output Les opérations d'entrée sont toutes définies à partir de deux classes abstraites : InputStream et Reader. InputStream permet de lire un flux d'octets provenant d'une source quelconque et Reader un flux de caractères. De la même manière, les sorties sont effectuées à partir de deux classes abstraites : OutputStream et Writer. Deux exemples concrets sont fournis : entrées/sorties clavier-écran et dans un fichier. Pour plus de précision, se reporter à java.io et aux nombres classes spécialisées qui s'y trouvent. 5.1 Affichage à l'écran Cours Java 1.1 23 20/11/00 La classe System possède le stream de sortie standard appelé simplement : out. Il est possible d'afficher directement toute variable d'un type de base en le passant en paramètre de la fonction print ou println (passage à la ligne après affichage). Pour un objet, l'affichage peut être effectué grâce à la méthode toString () définie dans la classe Object. Si la méthode ne convient pas il faut la redéfinir dans la classe que l'on désire afficher. Toute classe héritant de la classe Object, l'affichage d'une structure polymorphe se fera sans problème. Pour afficher avec un seul appel plusieurs entités, il faut les préciser, dans l'ordre d'affichage, simplement séparées par un + (symbole de concaténation). System.out.print ("un certain texte " + unEntier + " ou " + unFloat + " ou " + unObjet.toString ()); 5.2 Lecture au clavier Illustré à partir d'un exemple qui montre l'usage que l'on peut faire des classes de java.io et java.lang.System. La classe System possède le stream d'entrée standard appelé simplement : in. Il est utilisé pour instancier la classe InputStreamReader qui va récupérer les entrées clavier. L'instance ainsi créée (bien que n'ayant pas été stockée dans une variable d'instance) va être utilisée pour créer une instance de BufferedReader qui va stocker dans un buffer les entrées clavier. Il est possible de créer une instance "virtuelle", dont la référence n'est pas stockée pour être ensuite explicitement libérée, grâce au garbage collector qui assure la libération de la place mémoire allouée dès que la référence n'est plus utilisée (!!à ne pas faire en C++!!). import java.io.* ; import java.lang.*; public class lecture { public static void main(String[] args) // la méthode main est susceptible d'avoir à transmettre une exception de type IOException // qu'elle ne va pas récupérer pour la traiter elle même. Elle doit donc le signaler. throws java.io.IOException { // L'instance myInput sait lire au clavier et stocker les informations lues. // pour pouvoir lire au clavier, il faut instancier l' InputStream avec System.in // (entrée standard) et instancier BufferedReader avec l' InputStream pour // pouvoir saisir plus d'un caractère. BufferedReader myInput=new BufferedReader(new InputStreamReader(System.in)); // Toute saisie est stockée dans un String. String c=new String(); // Résultat final souhaité pour la saisie. int resultat = 0; float autre = 0; // Programme de lecture, version explicite : à préférer // récupération de l'entrée clavier dans un String qui sert ici de buffer d'entrée c = myInput.readLine(); // la chaîne est convertie en Integer (instance de la classe prédéfinie Integer) // dont on extrait ensuite la valeur entière de type de base int resultat = Integer.valueOf(c).intValue(); // récupération de l'entrée clavier dans un String qui sert ici de buffer d'entrée Cours Java 1.1 24 20/11/00 c = myInput.readLine(); // la chaîne est convertie en Float (instance de la classe prédéfinie Float) // dont on extrait ensuite la valeur réelle de type de base float autre = Float.valueOf(c).floatValue(); // DEBUG : affichage du résultat pour contrôle System.out.println("resultat " + resultat + " " + autre); // Programme de lecture version condensée, pas toujours souhaitable. resultat = Integer.parseInt(myInput.readLine()); autre = Float.valueOf(myInput.readLine()).floatValue(); // DEBUG : affichage du résultat pour contrôle System.out.println("resultat " + resultat + " " + autre); } } 5.3 Entrées/Sorties dans un fichier Démonstration par l'exemple : Voici une classe qui va écrire dans un fichier une structure de données (ici une liste implantée dans un Vector) et la récupérer. import java.io.*; public class ListeStockable extends Liste // implantée à partir d'un Vector { // constructeur ListeStockable () { super (); } // pour écrire une liste dans un fichier public void writeOnFile (String dest_name) throws IOException { File destination_file = new File(dest_name); // création du fichier d'écriture FileOutputStream ostream = null; // déclaration du flux de sortie dans un fichier ObjectOutputStream oos; // déclaration du flux de sortie d'un Object int j; try { if (destination_file.exists()) { if (destination_file.isFile()) { // pour l'entrée au clavier de la réponse BufferedReader myInput = new BufferedReader(new InputStreamReader(System.in)); String reponse = new String (); Cours Java 1.1 25 20/11/00 if (!destination_file.canWrite()) throw new FileRWException("FileCopy: fichier destination " + "inaccessible en écriture: " + dest_name); System.out.print("Fichier " + dest_name + " déjà existant. Peut-on écraser son contenu ? (Y/N): "); System.out.flush(); reponse = myInput.readLine(); if (!reponse.equals("Y") && !reponse.equals("y")) throw new FileRWException("FileCopy: fichier écrasé."); } else throw new FileRWException("FileCopy: destination " + "n'est pas un fichier: " + dest_name); } // Tout est ok, on peut écrire dans le fichier // on ouvre le flux d'écriture dans le fichier ostream = new FileOutputStream(destination_file); // on précise que les données seront des Object oos = new ObjectOutputStream(ostream); for (j=0 ; j < taille ; j++) // on écrit les Object dans le fichier un après l'autre oos.writeObject(ith(j)); // placer dans le fichier un Object null pour signaler la fin oos.writeObject(null); } // Quoiqu'il arrive, toujours fermer le fichier finally { if (ostream != null) try { ostream.close(); } catch (IOException e) { ; } } } // pour lire une liste depuis un fichier public void readFromFile (String source_name) throws IOException, ClassNotFoundException { File source_file = new File(source_name); // création du fichier en lecture FileInputStream istream = null; // déclaration du flux d'entrée depuis un fichier ObjectInputStream ois; // déclaration du flux d'entrée d'un Object int j; Object t; boolean termine = false; try { // le fichier en lecture existe t'il avec les bons droits d'accès if (!source_file.exists() || !source_file.isFile()) throw new FileRWException("FileCopy: fichier source inexistant: " + Cours Java 1.1 26 20/11/00 source_name); if (!source_file.canRead()) throw new FileRWException("FileCopy: fichier source non accessible en lecture " + source_name); // tout est OK on peut lire le fichier // ouverture du flux d'entrée depuis le fichier istream = new FileInputStream(source_file); // on précise que les données lues seront des Object ois = new ObjectInputStream (istream); while (!termine) { t = ois.readObject(); if (t == null) termine = true; else putLast(t); } } // toujours fermer le fichier finally { if (istream != null) try { istream.close(); } catch (IOException e) { ; } } } } // permet de créer sa propre exception accompagnée d'un message class FileRWException extends IOException { public FileRWException(String msg) { super(msg); } } ATTENTION : la sauvegarde d'instances de classes ne résout pas un problème complexe qui est illustré par l'exemple suivant : Employé Le manager est un employé La secrétaire également Manager Secrétaire Employé Staff Manager Secrétaire ... Manager Secrétaire Cours Java 1.1 27 20/11/00 Après sauvegarde sur disque et restauration de la structure, on constate qu'une instance de secrétaire a été crée pour chaque manager alors qu'il s'agit en fait de la même personne. Staff Employ é Miss Hacker Manager Secrétaire Employ é Miss Hacker .... Manager Secrétaire Employé Miss Hacker Comme Miss Hacker ne doit pas avoir le don d'ubiquité, il faut modifier les méthodes pour pouvoir restaurer la structure telle qu'elle était au départ. Ce concept de persistance permet d'assurer qu'aucun duplicata non désiré d'instance ne sera crée. Une méthode "bricolée" permet d'arriver au bon résultat : 1_ Lors de la sauvegarde sur disque, numéroter les objets enregistrés grâce à un label. 2_ Vérifier avant de sauvegarder si l'objet n'a pas déjà été stocké. 3_ Si c'est le cas, remplacer l'objet par un indicateur suivi de son label. Ce stockage fait en sorte de ne stocker les instances qu'une seule fois et de faire référence au numéro d'ordre chaque fois qu'une référence vers une instance déjà stockée est détectée. Lors de la restauration, il faudra rétablir les références vers les instances à la place des labels stockés sur disque. Pour implanter le concept de persistance, il faut attendre le concept d'objet transient qui ne sera pas disponible dans la version 1.1 de java. 6. Packages Les classes de base de JAVA sont organisées en Packages et on trouvera en particulier le Package awt qui contient toutes les classes graphiques servant à construire des interfaces utilisateurs. Une classe désirant utiliser ce Package devra déclarer : import java.awt.Button; ou encore import java.awt.*; // pour importer toutes les classes de awt, utile si on en utilise plusieurs class useAwt { Button b; // classe présente dans awt ... } Les Packages permettent la conception de groupes de classes et d'interfaces. Ainsi on peut limiter l'accès à des groupes de classes explicitement désignés. Ceci a l'avantage d'éviter des conflits sur les noms de classes. Des classes appartenant à différents Packages peuvent ainsi avoir le même nom pour éviter d'avoir à rallonger inutilement les noms de classes avec comme seul but de lever les ambiguïtés. L'autre avantage plus classique étant d'effectuer des regroupements thématiques afin d'aider à la recherche d'informations dans les bibliothèques de classes. Cours Java 1.1 28 20/11/00 Les Packages permettent donc de regrouper et d'organiser hiérarchiquement des classes. Il faut pour cela utiliser un fichier par classe. Avant l'entête des classes du package PackX écrire : package PackX; public class ClasseY { ... } Les classes du même Package sont à mettre dans le même répertoire. Pour créer une hiérarchie de Packages il faut créer une hiérarchie de répertoires équivalents dont la racine est le répertoire des classes. PACK1 PACK2 HOME REP1 REP2 JAVA cl1.java cl2.java cl3.java PACK3 PACK4 PACK5 Toutes les classes situées dans le répertoire PACK2 déclarent avant leur entête :Package PACK2; Pour simplifier l'accès à un élément, on positionne une variable d'environnement appelée CLASSPATH qui précisera le chemin d'accès jusqu'au répertoire JAVA, sous lequel on doit trouver tous les répertoires contenant les Packages propres du développeur. Exemple : Pour mettre en place les 'package', on suppose les fichiers suivants : /home/xxx/JAVA/TP1/PointND.java /home/xxx/JAVA/TP1/Comparable.java /home/xxx/JAVA/TP2/Ensemble.java /home/xxx/JAVA/TP2/EnsembleComparable.java /home/xxx/JAVA/TP2/Main.java 1) Modifier le fichier .env.csh en ajoutant la ligne suivante : setenv CLASSPATH .:/home/xxx/JAVA Attention, une erreur ici et rien ne marche !!! 2) sauver et taper : source .env.csh pour re-exécuter le .env.csh 3) les fichiers qui sont dans TP1 doivent déclarer être dans un package et mettre en première ligne : package TP1; donc le package s'appelle TP1. 4) le Main et EnsembleComparable doivent importer les classes du package TP1 : import TP1.*; Attention : Le Main ne doit pas se trouver dans un répertoire d'où il importe des classes. Ainsi, si Ensemble et EnsembleComparable déclarent faire partie du package TP2 et que le main importe les classes des packages TP1 et TP2, il devra donc se situer hors de ces deux packages, dans un autre répertoire. Cours Java 1.1 29 20/11/00 7. Interfaces (mot clef implements) Une Interface (au sens JAVA et non IHM) est une collection de descriptions (signatures) de méthodes sans implantations (deffered). Elle propose un modèle de comportement (ex. Cloneable). Les Interfaces sont déclarées dans des fichiers sources, à raison d'une Interface par fichier. Une classe hérite d'une seule classe parente mais n'est pas limitée en nombre d'Interfaces qu'elle peut utiliser. Une Interface ne peut être instanciée. Exemple de création d'interface : package XXX; public interface interf extends int1, int2 ... ; // "héritage" d'interfaces { // toutes les méthodes sont public abstract // toutes les variables sont public ou static ou final ... } Exemple : public interface sortable { public int compare (sortable a); } class window extends rectangle /* héritage simple */ implements sortable; { public int compare (sortable a) // retourne -1 0 ou 1 selon < = ou > {window wa = (window) a; if (z /* le courant */ < wa.z) {....} else {....} } public static main ( String args [] ) { window w1 = new window (...); window w2 = new window (...); if (w1.compare (w2) < 0 ) {...} ... } 8. AWT et gestion des événements Les événements du type "java.awt.WindowEvent" permettent de prendre en compte les actions que l'utilisateur réalise sur une fenêtre. Ainsi, la sélection de la case Quit dans le menu ajouté par le window manager à chaque fenêtre entraîne un appel de la méthode "void windowClosing(WindowEvent e)" du WindowListener déclaré pour cette fenêtre. La fonction System.exit(code) permet de quitter la machine virtuelle java en retournant le code spécifié au shell. Cours Java 1.1 30 20/11/00 Les événements du type "java.awt.event.KeyEvent" permettent de prendre en compte les actions réalisées au clavier. Ainsi, lorsqu'on tape sur une touche du clavier, le focus étant sur un composant implantant l'interface "java.awt.event.KeyListener", les méthodes suivantes sont appelées (dans l'ordre) : public void KeyPressed (KeyEvent e) : lors d'un appui sur la touche. public void KeyTyped (KeyEvent e) : lors d'une suite appui-relaché sur la touche. public void KeyReleased (KeyEvent e) : lors du lâché de la touche. Les événements du type "java.awt.event.MouseEvent" permettent de gérer les actions souris sur le composant implantant l'interface "java.awt.event.MouseListener". Les méthodes suivantes sont définies pour cette interface : public void mouseClicked (MouseEvent e) : lors d'un click souris public void mousePressed (MouseEvent e) : lors de l'appui sur un bouton de la souris public void mouseReleased (MouseEvent e) : lors du relâchement d'un bouton de la souris public void mouseEntered (MouseEvent e) : lors de l'entrée de la souris sur le composant public void mouseExited (MouseEvent e) : lors de la sortie de la souris sur composant 8.1.1 Identification du bouton cliqué Exemple : public void moussePressed (MouseEvent e) { // click sur le bouton droit if ((e.getModifiers() & java.awt.event.InputEvent.BUTTON3_MASK) != 0) { // action à effectuer quand bouton droit cliqué } else { if ((e.getModifiers() & java.awt.event.InputEvent.BUTTON2_MASK) != 0) { // action à effectuer quand bouton du milieu cliqué } else { // action à effectuer quand bouton gauche cliqué } } 8.2 Version simple Illustration par un exemple : Prise en compte des événements clavier : Cette prise en compte doit être effectuée par la mise en place des éléments suivants : // Classe définissant les événements clavier import java.awt.event.KeyEvent; // interface permettant la mise en œ uvre des sous-programmes de récupération des // événements. import java.awt.event.KeyListener; Cours Java 1.1 31 20/11/00 // classe mise en oeuvre classX implements KeyListener { // constructeur X (… ) { … // permet de préciser que la classe attend les entrées clavier this.addKeyListener(this); } // Implantation de toutes les méthodes abstraites définies dans KeyListener public void keyTyped (KeyEvent e) { //any key } public void keyReleased (KeyEvent e) { } public void keyPressed (KeyEvent e) { switch(e.getKeyCode()) {… // pour que le parent puisse informer le window manager de la destruction // demandée de la fenêtre case java.awt.event.KeyEvent.VK_ESCAPE : … // dans le cas où on récupère l'événement dans une fenêtre qui // est fille de la fenêtre principale de l'application (seule connue du // window manager), il faut la transférer pour quitter proprement // l'application WindowEvent we = new WindowEvent ((Window) getParent(), java.awt.event.WindowEvent.WINDOW_CLOSING); getParent().dispatchEvent(we); break; case … } } } 8.3 Version complète (plus complexe) Le traitement des événements est séparé en deux parties : - l'objet qui souhaite recevoir un événement donné, - le récepteur d'événement (Listener). Un récepteur d'événement est affecté à un certain ensemble d'événements (un pour la souris, un pour le clavier ...) et doit déclencher des actions en réponse aux événements. Le code de traitement de l'événement est placé dans le récepteur. En fait il doit s'agit de l'appel d'une fonction de callback, déclarée dans la classe souhaitant récupérer l'événement. Cours Java 1.1 32 20/11/00 Exemple : import java.awt.*; public class Fenetre extends Frame { // attributs protected Panel centerPanel; // panel : structure qui contient le canvas de tracé protected MyCanvas canvas; // pour tracer et récupérer des événements // event adaptor : on declare une instance de la classe // qui servira à indiquer que le canvas souhaite recevoir les événements // de type "intéraction à l'aide de la souris" protected MouseAdaptator mouseAdaptator; // même chose avec les entrées clavier protected KeyAdaptator keyAdaptator; // constructeur public void Fenetre () { super(); // appel du constructeur de la classe parente centerPanel = new Panel(); // création du panel et du canvas canvas = new MyCanvas (); // on place le canvas dans le panel centerPanel.setLayout(new GridLayout (1,1)); // 1 ligne 1 colonne centerPanel.add(canvas); // le canvas est placé dans la première colonne this.add("Center", centerPanel); // la fenêtre contient le panel centré // il faudrait le faire relativement à la taille de la fenêtre canvas.setSize(380, 240); // taille du canvas canvas.setVisible(true); // qui sera visible // ----------> lien entre événement et canvas : réception des événements souris mouseAdaptator = new MouseAdaptator(); canvas.addMouseListener(mouseAdaptator); // ----------> lien entre événement et canvas : réception des entrées clavier keyAdaptator = new KeyAdaptator(); canvas.addKeyListener(keyAdaptator); show (); // affichage de la fenêtre } // Fenêtre // modification de la structure de données qui contient les points définissant le tracé public void changerPoints (Point2D tabp [][], int nbPoints, int nbInscrits) { // stockage des points décrivant le tracé dans le tableau de points canvas.setPoints (tabp, nbPoints, nbInscrits); } // changerPoints //--------------------------------------------------------------------// la suite du code est liée à la gestion des événements relatifs // à la Fenêtre //--------------------------------------------------------------------// mise en correspondance de la fonction de callback (focus) avec // un événement (événement lié à la souris) Cours Java 1.1 33 20/11/00 class MouseAdaptator implements java.awt.event.MouseListener { // ici on choisit de ne traiter que l'événement "bouton enfonce" public void mousePressed(java.awt.event.MouseEvent event) { focus(event); } // ceux non utilisés doivent être quand même implantés même vides // sinon la classe serait abstraite public void mouseClicked(java.awt.event.MouseEvent event) {} public void mouseReleased(java.awt.event.MouseEvent event) {} public void mouseEntered(java.awt.event.MouseEvent event) {} public void mouseExited(java.awt.event.MouseEvent event) {} } // MouseAdaptor // mise en correspondance de la fonction de callback (exit) avec // un événement (événement lié à une entrée clavier) class KeyAdaptator implements java.awt.event.KeyListener { public void keyPressed(java.awt.event.KeyEvent event) { exit(event); } // ceux non utilisés doivent être quand même implantés même vides // sinon la classe serait abstraite public void keyTyped(java.awt.event.KeyEvent event) {} public void keyReleased(java.awt.event.KeyEvent event) {} } // KeyAdaptor // fonctions de callback qui seront appelées quand un événement aura lieu // dans la fenêtre // on quitte avec la touche ESCAPE public void exit (java.awt.event.KeyEvent event) { // si le code stocké dans la sdd de l'événement correspond // à la touche ESCAPE alors on quitte l'application if(event.getKeyCode() == java.awt.event.KeyEvent.VK_ESCAPE) // tout code nécessaire pour quitter proprement doit être // inséré ici System.exit(0); } // exit // on provoque un réaffichage avec un click de souris //(non nécessaire ici : créée juste pour tester) public void focus (java.awt.event.MouseEvent event) { canvas.repaint(); } // focus Cours Java 1.1 34 20/11/00 } // Fenêtre La trame de la classe MyCanvas pouvant être la suivante : import java.awt.*; class MyCanvas extends Canvas { // attributs // stockage des sommets des segments à tracer public Point2D tabp [ ][ ]; // constructeur MyCanvas () {} // modification du tableau contenant les sommets des segments à tracer public void setPoints ( Point2D tabPoints [ ] [ ], int nbPoints, int nbInscrits) { // récuperation des points à tracer} public void paint(Graphics g) // contexte graphique { // tracé des segments indiqués par les points stockés dans tabp} } 9. Threads Multithreading = multitâche en parallèle dans un seul programme. 4 modifications sont à apporter à une applet : 1_ elle doit implanter l'interface Runnable 2_ ajouter une variable d'instance pour recevoir le thread 3_ modifier la méthode strart ( ) pour limiter son rôle au lancement d'un thread 4_ créer une méthode run ( ) Exemple : class xxx extends java.applet.Applet implements Runnable { Thread runner; // de java.lang ( de base ) public void start ( ) // active le thread runner { if ( runner == null ) { runner = new Thread ( this ); runner.start ( ); } else if ( runner.isAlive ( ) ) { runner.resume ( ); } public void stop ( ) // suspend le thread quand la page est quittée { if ( runner != null && runner.isAlive ( ) ) { runner.suspend ( ); } } Cours Java 1.1 35 20/11/00 public void destroy ( ) { ... // idem stop quand le browser est quitté } } public class MC extends java.applet.Applet implements Runnable { Thread runner; // de java.lang ( de base ) public void strart ( ) { // crée et démarre le thread if ( runner == null ) { runner = new Thread ( this ); runner.start ( ); } } // le corps de l'applet doit être mis dans une méthode run public void run ( ) { // tout ce qui doit s'exécuter dans le thread } public void stop ( ) { if ( runner != null ) { runner.stop ( ); runner = null; } } 10. Exemple import java.awt.Graphics; import java.awt.Font; import java.awt.Color; // ou écrire import java.awt.*; public class HelloAgainApplet extends java.applet.Applet; // classe parente // Package classe // public obligatoire pour les applets => visible pour les classes du programme JAVA { Font f = new font ("TimesRoman", Font.Bold, 36); // instance de la classe Font de java.awt public void Paint (Graphics g) // classe qui fournit des comportement de tracé { g.setFont (f); // police par défaut g.setColor (Color.red); // classe Color, couleur définie pour g g.drawString ("Hello again", 5, 50); // pos en x et en y dans la fenêtre } } La méthode paint est abstract et définie dans Applet. Si on souhaite l'utiliser il faut donner son implantation. Elle est public car déclarée comme cela dans Applet. Pour exécuter une Applet il faut ensuite créer un fichier .html Cours Java 1.1 36