Cours de JAVA Programmation avancée en Java Emmanuel ADAM Institut des Sciences et Techniques de Valenciennes Université de Valenciennes et du Hainaut-Cambrésis Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 1 Introduction à JAVA ✎ Présentation ✎ Concepts ✎ Gestion de la mémoire ✎ Gestion de classes Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 2 Présentation de JAVA Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 3 Petite histoire 1991, chez SUN est créé le langage OAK (pour interface entre appareil ménagers et ordinateurs) 1994, Oak se tourne vers Internet et devient Java 1995, Java est intégré à Netscape 1998, Version 1.2 de Java 2000, Version 1.3 de Java 2002, Version 1.4 de Java 2004, Version 1.5 de Java / 1.6 en 2006 Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 4 Télécharger Java Sur son site (http://java.sun.com/), SUN propose les différents Kits de Développement Java (JDK) SUN propose également une documentation très complète Sur Internet, grand nombre de sources, de projets open-sources et de documentations [Ex : "Thinking in Java" de B. Eckel] Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 5 Définition des variables d'environnement Pour compiler en java, il faut définir quelques variables d'environnement : Chemin d'accès aux exécutables. Par exemple : SET PATH=%PATH%;C:\Sun\SDK\bin Chemin d'accès aux librairies. Par exemple : SET CLASSPATH=.;C:\Sun\SDK\lib Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 6 Les concepts de JAVA Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 7 La Compilation & JAVA Le principal atout de JAVA concerne sa portabilité. Celle-ci est possible par la notion de ByteCode. JAVA ne produit pas un code natif, directement exécutable. JAVA produit un code intermédiaire, le ByteCode, interprétable par une machine virtuelle. Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 8 La Compilation "classique" Source A‘ Source B‘ Source A'‘ Source B'‘ Source A''‘ Source B''‘ Compilation & Linkage sur machine M1 Compilation & Linkage sur machine M2 Compilation & Linkage sur machine M3 Exécutable pour Machine M1 Exécutable pour Machine M2 Exécutable pour Machine M3 Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 9 La Compilation Java Source A Source B Compilation & Linkage sur machine M ByteCode Exécution sur machine M1 Exécution sur machine M2 Exécution sur machine M3 Interprétation par machine virtuelle (Java Virtual Machine) spécifique au système d'exploitation Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 10 Code natif vs ByteCode (+) rapidité d'exécution (-) source pas toujours portable (-) recompiler pour changer de système (+) source portable (+) Bytecode portable (-) moins rapide car interprété Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 11 Source portable Les types primitifs sont totalement spécifiés. Ils ne dépendent pas de l'architecture de la machine : Les entiers, réels, etc... sont toujours définis sur le même nombre de bits. Génération du ByteCode par le compilateur javac Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 12 Gestion de la mémoire En JAVA, tout est objet. A chaque objet créé, une zone mémoire est dynamiquement allouée On ne peut détruire explicitement les objets Dès qu'un objet n'est plus utilisé (sortie de boucle, ...), il est détruit. Le Garbage Collector (ramasse-miettes) se charge de récupérer la mémoire. Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 13 Exemple de compilation Hello.java public class Hello { public static void main(String args[]) { System.out.println("Hello !!!"); } } Source ByteCode Hello.class C:\Java>javac Hello.java Êþº¾ ()V (Ljava/lang/String;)V ([Ljava/lang/String;)V <init> Code Hello Hello !!! Hello.java LineNumberTable Ljava/io/PrintStream; SourceFile java/io/PrintStream java/lang/Object java/lang/System main out println ! *· ± % ² ¶ ± C:\Java> java Hello Hello !!! Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 14 Gestion de la mémoire en JAVA Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 15 Ramasse-Miettes Ressource mémoire limitée Gérer la mémoire ==> Ne pas libérer une zone mémoire utilisée par un objet Ne pas bloquer une zone mémoire libérée par un objet détruit Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 16 Ramasse-Miettes Perte de mémoire : Fuites graves (hard leaks) : inexistence de système de nettoyage Géré par le GC -Garbage Collector la surveillance de l'utilisation des objets, la détermination des objets devenus inutiles, la récupération des ressources libérées. Fuites légères (soft leaks) : un programme ne libère pas la mémoire d'objets inutilisés À gérer par à la programmation ob = null; signale l'abandon de l'objet ob Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 17 Fonctionnement de la Gestion de la mémoire La Machine Virtuelle Java (JVM) surveille le nombre nb de références à chaque objet. nb=0 ==> objet inutilisé ==> libérer mémoire Le processus GC est lancé périodiquement de façon asynchrone Le GC lance la méthode finalize() de chaque objet non référencé Le programme peut terminer avant que le GC ne soit lancé Impossibilité de prévoir le lancement du GC Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 18 Ramasse-Miettes Synchronisé Possibilité de lancer explicitement le GC : System.gc(); Appel demandé, non lancé immédiatement Indiquer à la JVM le passage en mode totalement synchrone : java -noasyncgc monProg Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 19 Exemple de GC 1/2 public class PersonneF { String nom, prenom; static int nb = 0; int no = 0; PersonneF(String _nom, String _prenom) { nom = _nom; prenom = _prenom; no = ++nb; } } public void finalize() { System.out.println("fin de l'objet Personne " + no); } Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 20 Exemple de GC 2/2 public class TestPersonneF { TestPersonneF(){} fin de l'objet fin de l'objet fin de l'objet void go(int nb) fin de l'objet { fin de l'objet for(int i=0; i<nb; i++) fin de l'objet PersonneF p = new PersonneF("a"+i, "aa"+i); fin de l'objet } fin de l'objet fin de l'objet public static void main(String args[]) fin de l'objet { Personne Personne Personne Personne Personne Personne Personne Personne Personne Personne 10 9 8 7 6 5 4 3 2 1 int nb = 10; if (args.length == 1) nb = Integer.parseInt(args[0]); TestPersonneF tp tp.go(); System.gc(); } = new TestPersonneF(); } Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 21 Finalisation d'un objet Si finalize() est définie, elle est automatiquement appelée par un thread spécialisé (Finalizer) Intérêt : terminer proprement un objet Le sauvegarder,... Ou le raccrocher à une référence ! Attention : finalize() appelée 1 seule fois par objet Lancer la finalisation avant le GC : System.runFinalization(); Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 22 Informations sur la mémoire long taille = Runtime.getRuntime().totalMemory(); retourne la taille totale de la mémoire de la machine virtuelle java long taille = Runtime.getRuntime().freeMemory(); retourne la quantité de mémoire libre du système long taille = Runtime.getRuntime().maxMemory(); retourne la quantité maximale de mémoire utilisable par la JVM Nombres en octets Augmenter la taille de la mémoire virtuelle : -Xmx512M MonProg java Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 23 Eléments de base de JAVA Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 24 Tout est Objet (ou presque...) Tous les éléments en JAVA dérivent de la classe Object. Tous sauf les primitives (8 en tout) représentant des types simples. A chaque type de primitive correspond une classe d'objet. Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 25 Les primitives : des types simples Nom Taille Minimum boolean 1 bit false true Boolean char 16 bits Unicode 0 Unicode 216-1 Character byte 8 bits -128 127 Byte short 16 bits -215 215-1 Short int 32 bits -231 231-1 Integer long 64 bits -263 263-1 Long float 32 bits (+/-)1.4 10-45 (+/-)3.4 1038 Float double 64 bits (+/-)4.9 10-324 (+/-)1.8 10308 Double void - - Void - Maximum Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis Classe 26 Les objets simples Tout objet Java hérite de la classe Object : Object Boolean Byte Character Short Number Integer Void Long Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis Float Double 27 Primitives <-> Objets Passer d'une primitive à l'objet correspondant : int i = 5; Integer obj = new Integer (i); Dans la classe Number sont définies les méthodes de conversion intValue, doubleValue, floatValue, ... int j = obj.intValue(); Dans la classe Object est définie la méthode toString convertissant un objet en chaîne. Cette fonction est surchargée dans les classes d'objets numériques. Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 28 Auto(un)boxing : Primitives <-> Objets implicite Passer d'une primitive à l'objet correspondant : double d1 = 5.1; Double od1 = d1; Double od2 = 5.3; Passer d'un objet à la primitive correspondante : double d3 = od2; Attention au réel simple précision : Float f = 5.7f; Attention au coût de création d'objets Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 29 Exemples de conversions public class TestNum { public static void main(String arg[]) { double d1 = 5.1; // d1 est un réel double précision Double od1 = new Double(d1); // objet Double de la valeur de d1 Double od2 = 5.2; // objet Double de valeur 5.2 double d2 = od1.doubleValue(); // définition d'une primitive de la valeur de od1 double d3 = od1; // définition d'une primitive de la valeur de od1 System.out.println(" d1 , od1 , od2 , d2 , d3 "); System.out.println("" + d1 + " , " + od1 + " , " + od2 + " , " + d2 + " , " + d3); } } Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 30 Les Tableaux Un tableau en Java est un type d'objet simple (il ne contient que l'attribut length). Tableau simple : int tab [] = new int [10]; Tableau multi-dimensionnel : double cube[][][] = new double[3][3][3]; Initialisation : int tab[] = {1, 2, 3, 4, 5}; Création et Passage de tableau en argument : afficheTab(new int[]{1,2,3}); Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 31 Les opérateurs (cf. C++) Arithmétiques : pour tout nombre x, on peut écrire : x++; x--; ++x; --x; x+=2; x-=2; x*=2; x/=2; x%=2 (x = x modulo 2) Logiques : pour tout booléen x et y, non x !x x et y x & y ou x && y x ou y x | y ou x || y x ou exclusif y x ^ y (test économe) (test économe) Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 32 Structures de contrôle Les structures de contrôle utilisées en Java sont fortement inspirées de celles du langage C ou C++ : if ; else ; while ; do ; for ; break ; goto Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 33 Branchement conditionnel (1/2) Si ... Alors ... Sinon if (test) { action1_si_test_vrai; action2_si_test_vrai; } else { action1_si_test_faux; action2_si_test_faux; } Le test est de la forme : a ; !a ; a & b ; a & !b ; x<y ; x == y; x != y ; ... Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 34 Branchement conditionnel (2/2) Branchement selon un choix multiple : switch (expression) { case valeur_1 : actions; break; case valeur_2 : actions; break; case valeur_3 : actions; break; default : actions si valeur inconnue; } Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 35 Boucle "Tant que" while (test) { actions; } do { actions; } while (test); Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 36 Boucle "Pour" int i; for(i=0; i<5; i++) // ou for(int i=0; i<5; i++) { actions; } int add(int ... tab) { int som=0; for (int val : tab) som += val; return x; } ... int res = add(15,22,13,64); Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 37 Sorties de boucles L'instruction break permet de sortir d'une boucle avant sa fin "normale". L'instruction continue passe le reste de la boucle, mais n'en sort pas. L'instruction goto label subsiste encore. Le label doit alors être défini (et suivi de : ). Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 38 Programmation Objet en JAVA Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 39 Concept Objet : rappels Tout objet dérive d' (instancie) une classe Une classe est composée de membres Les membres sont : des attributs (champs), définissant l’état d'un objet, des méthodes (fonctions, procédures) agissant sur ou en fonction des attributs, un ou des constructeurs, initialisant l'objet. Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 40 Exemple de classe La classe suivante représente une personne: Nom de la classe commençant par une class Personne { majuscule String nom, prenom; int age; constructeur Personne() Attributs { nom = new String(""); prenom = new String(""); age = 18; méthode } void affichePersonne() { System.out.println(prenom + " " + nom + ", age : " + age); } } Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 41 Exemple d'utilisation d'une classe class Personne C:\> javac TestPersonne.java {…} C:\> dir *.class TestPersonne.class Personne.class public class TestPersonne { C:\> java TestPersonne public static void main(String args[]) { Personne p1 = null; Personne p2 = new Personne(); System.out.println(p1); System.out.println(p2); p2.affichePersonne(); p1.affichePersonne(); } } Classe@adresse mémoire virtuelle null Personne@ea2dfe , age : 18 Exception in thread "main" java.lang.NullPointerException at TestPersonne.main(TestPersonne.java:26) Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 42 Utilisation des Objets en Java En Java, on manipule des références aux objets, // construction d'un objet Personne, f1 reçoit son adresse en mémoire virtuelle Personne f1 = new Personne(); f1.nom = "Simon"; // f2 reçoit la valeur de f1, et donc pointe vers le même objet Personne f2 = f1; System.out.println(f1.nom + "-" +f2.nom); // Simon – Simon f2.nom = "hello"; System.out.println(f1.nom + "-" +f2.nom); // hello – hello Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 43 Objets anonymes Il n’est pas nécessaire de donner un nom à un objet: … public class TestPersonne { public static void main(String args[]) { Personne [] tableau = new Personne[5]; for (int i=0; i<5; i++) { tableau[i] = new Personne (); tableau[i].age += i; } for (int i=0; i<5; i++) tableau[i].affichePersonne(); } } Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis , , , , , age age age age age : : : : : 18 19 20 21 22 44 Héritage En java, Si une classe A hérite d'une classe B, elle possède tous les attributs et méthodes de B non privés Notation : class Animal {...} class Hamster extends Animal {...} P a s d ' h é r i t a g e m u l t i p l e Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 45 Héritage : généricité et surcharge (1/4) Une classe fille peut surcharger une méthode d'une classe mère L'objectif de l'héritage est la généricité : appliquer le même schéma d'actions à des objets de type différents Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 46 Héritage : généricité class Animal { String nom; int nb_pattes; Animal() { nom = new String(""); nb_pattes = 0; } void affiche() { System.out.println("Animal : " + nom + ", nb de pattes = " + nb_pattes); } } et surcharge (2/4) public class TestAnimaux { public static void main(String args[]) { Animal a = new Animal(); Hamster h = new Hamster(); a.nom = "ani"; h.nom = "ham"; a.affiche(); h.affiche(); } } class Hamster extends Animal { Animal : ani, nb de String couleur_pelage; Hamster() Hamster : ham, nb { nb_pattes = 4; Animal : ani, nb de couleur_pelage = "gris"; } Hamster : ham, nb void affiche() { System.out.println("Hamster : " + nom + ", nb de pattes = " + nb_pattes + ", couleur = " + couleur_pelage); } } Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis Animal tab[] = {a, h}; tab[0].affiche(); tab[1].affiche(); pattes = 0 de pattes = 4, couleur = gris pattes = 0 de pattes = 4, couleur = gris 47 Héritage : généricité et surcharge (3/4) Généricité = utiliser le même code sur tous types d'objet Les objets Java héritent tous de la classe Object => utiliser le type Object et le "casting" Rq. : instanceof permet de retrouver la classe d'origine d'un objet Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 48 Héritage : généricité et surcharge (4/4) Exemple : un tableau de 4 objets de 2 types différents Integer i1 = new Integer(11); Integer i2 = new Integer(12); Personne p1 = new Personne(); Personne p2 = new Personne(); p1.nom = "Nicolas"; p2.nom = "Jose"; Object tab [] = {i1, p1, i2, p2}; for(int i=0; i<4; i++) { Object o = tab[i]; if (o instanceof Integer) System.out.println("Integer, val = " + (Integer)o ); else if (o instanceof Personne) { Personne f = (Personne )o; System.out.println(" Personne, nom = " + f.nom ); } else System.out.println("Objet indéterminé" ); } casting Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 49 Comparer les objets en Java (1/2) Le test == ne compare que les valeurs des références Personne p1 = new Personne(); Personne p2 = new Personne(); p1.nom = "Samia" ; p2.nom = "Samia" ; System.out.println(p1 == p2); // false System.out.println(p1 == p1); // true Solution : surcharger la méthode equals de la super class Object Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 50 Comparer les objets en Java (2/2) Il faut comparer chaque champs de la classe class Personne // extends Object par défaut {.... public boolean equals(Object o) { boolean rep; Personne p = (Personne)o; rep = nom.equals(p.nom) && prenom.equals(p.prenom) && age==p.age; return rep; } } public class TestEgalite { public static void main(String args[]) { Personne p1 = new Personne(); Personne p2 = new Personne(); p1.nom = "Samia" ; p2.nom = "Samia" ; System.out.println(p1 == p2); System.out.println(p1.equals(p2)); } false true Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 51 Protection des attributs et méthodes Un attribut ou une méthode précédé de private n'est accessible que par sa classe, protected est accessible aux sous-classes et aux classes voisines, public est accessible à toutes classes. private protected n’est plus utilisé, Par défaut : protected. Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 52 Exemple de protection La classe suivante représente une personne: class PersonneP { public String nom, prenom; // accessible par toutes les classes private int noSecu; // accessible par cette classe uniquement int noTel; //accessible par cette classe et classes voisines int age; //accessible par cette classe et classes voisines Personne() { nom = new String(""); prenom = new String(""); age = 18; noSecu = 0; noTel = 0; } public void affichePersonne() // toutes les classes peuvent appeler cette méthode { System.out.println(prenom + " " + nom + ", age : " + age); } } Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 53 Exemple d'utilisation d'attributs protégés class PersonneP {…} public class TestPersonneP { public static void main(String args[]) { PersonneP p = new PersonneP(); System.out.println(p); p.affichePersonne(); p.noSecu = 5; } >javac TestPersonne.java TestPersonne.java:26: noSecu has private access in Personne p.noSecu = 5; } ^ 1 error Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 54 Membres particuliers : Constructeurs Un constructeur est appelé automatiquement à la création de l'objet Le constructeur permet d'initialiser un objet Le constructeur d'une classe porte le nom de cette classe. Exemple : class Fenetre { String nom; Fenetre () {nom = "";} // constructeur par défaut //Fenetre (String nom) {this.nom = nom;} Fenetre (String _nom) {nom = _nom;} } Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 55 Membres particuliers : This Le champ this d'une classe se réfère à l'instance de l'objet en cours de traitement. Il peut être utilisé : - Dans un constructeur, - Pour passer une référence à l'objet - class Fenetre { ObjetGraphique og = null; … public void affiche() { og.afficheGraphique( this ); }… } - Pour retourner une référence à l'objet - class Fenetre { .... Fenetre changeNom(String nom2) { nom = nom2; return this; } } - Pour lier deux objets Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 56 Héritage et constructeurs Si la classe A hérite de la classe B, le constructeur de A fait automatiquement appel au constructeur par défaut de B. super permet de choisir le constructeur de la classe mère : class B { ... B(){...} B(int i){...} } class A extends B { ... A() {...} A(int i, int j) {super(i); ...} A(int i, int j, int k) {this(i,j); ...} } Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 57 Appel de la méthode initiale Soit la classe A héritant de la classe B, A surchargeant affiche() de B A peut appeler affiche() de B par : super.affiche(); On ne peut appeler la méthode de la super super classe Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 58 Autres mots-clés : final final définit : un attribut invariable, dont la valeur ne peut être modifiée que par le constructeur final int noSecu; une méthode qui ne peut être surchargée, final void affichePersonne(){…} une classe qui ne peut être héritée. final class Personne {…} Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 59 Autres mots-clés : static (1/2) static définit un membre commun à toutes les instances de la classe On parle de membre de classe par opposition à membre d'instance Une variable de classe est indépendante de l'objet, elle existe dès le premier appel à la classe. Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 60 Autres mots-clés : static (2/2) Seule une méthode de classe peut utiliser des variables de classe Une méthode de classe ne peut être surchargée dans les sous-classes Utilisation des membres de classe : compteur d'objet, optimisation (définition de constante), définition de librairies, … Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 61 Utilisation de static (1/4) class Personne { String nom, prenom; static int nbPersonnes = 0; final int noPersonne; // définition de la variable statique Personne(String _nom, String prenom) { nom = _nom; this.prenom = prenom; noPersonne = ++nbPersonnes; } } // constructeur avec paramètres public String toString() // surcharge de la méthode héritée de Object { return (prenom + " " + nom + ", no personne = " + noPersonnes ); } Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 62 Utilisation de static (2/4) public class TestPersonne { public static void main(String args[]) { Personne p1 = new Personne("aa", "a"); // Personne.nb_personne Personne p2 = new Personne("bb", "b"); // Personne.nb_personne Personne p3 = new Personne("cc", "c"); // Personne.nb_personne Personne p4 = new Personne("dd", "d"); // Personne.nb_personne Personne p5 = new Personne("ee", "e"); // Personne.nb_personne System.out.println(p1); System.out.println(p2); System.out.println(p3); System.out.println(p4); System.out.println(p5); a aa, no personne = 1 } } b bb, no personne = 2 1 2 3 3 3 c cc, no personne = 3 d dd, no personne = 4 e ee, no personne = 5 Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 63 Utilisation de static (4/4) class Personne { … } static int retourneNbPersonnes() { return (no_personne); } public class TestPersonne { public static void main(String args[]) { Personne p1 = new Personne("aa", "a"); Personne p2 = new Personne("bb", "b"); nombre d'objets Personne crees = 2 // nb_personne 1 // nb_personne 2 int nb_personnes = Personne.retourneNbPersonnes(); } } System.out.println("nombre d'objets Personne crees = " + nb_personnes); Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 64 Autres mots-clés : abstract (1/2) abstract associé à une méthode permet de ne pas lui donner de corps. Si une méthode est abstraite, sa classe doit être définie comme abstraite. Une classe abstraite ne peut être instanciée. L'abstraction : définir un moule général pour les classes dérivées. Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 65 Autres mots-clés : abstract (2/2) abstract class Animal { } String nom; int nb_pattes; Animal() { nom = new String(""); nb_pattes = 0; } abstract void affiche(); class Mamifere extends Animal { Mamifere() { nb_pattes = 4; } void affiche() { System.out.println("Mamifere : " + nom + ", nb de pattes = " + nb_pattes); } } public class TestAnimaux { public static void main(String args[]) { Mamifere m = new Mamifere(); m.nom = "mami"; m.affiche(); } } Mamifere : mami, nb de pattes = 4 // Animal a = new Animal(); n'est pas possible !!! Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 66 Interface : une "classe vide" Une interface est une classe : ne contenant que les entêtes de méthodes (public par défaut) ne contenant que des attributs constants (de type static et final). Notation : interface EtreVivant { String type = "etre vivant"; d'initialiser l'attribut void naitre(); } // obligation class Animal implements EtreVivant {… } Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 67 Implémentations multiples Pas d'héritage multiple en java, mais possibilité d'implémentation multiple: Notation : interface EtreVivant {…} interface EtreMortel extends EtreVivant { } void mourir(); interface EtreSpirituel { void philosopher(); } class Animal implements Etre_vivant, EtreMortel {…} class EtreHumain extends Animal implements EtreSpirituel { … } Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 68 Interface pour regrouper les constantes Les attributs des interfaces sont statiques et finaux par défaut possibilité de créer des groupes de constantes interface Couleur { int BLANC = 999, NOIR = 000, GRIS = 555, BLEU = 900, ROUGE = 090, VERT = 009; } public class TestCouleur { public static void main(String arg[]) { } } int couleur_a = Couleur.BLEU; System.out.println(couleur_a); Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis // ==> 900 69 Enumérations Possibilité de définir des énumération sans interface : enum nom {VALEUR1, ...} enum Couleur {BLANC, NOIR, GRIS, BLEU, ROUGE, VERT}; public class TestCouleur { public static void main(String arg[]) { } } Couleur a = Couleur.BLEU; System.out.println(a); // ==> BLEU Utilisable dans les switch : Couleur c = Couleur.BLANC; switch (c) { case(BLEU): System.out.println("c'est bleu"); break; case(BLANC): System.out.println("c'est blanc"); break; } Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 70 Classes internes Pour grouper les classes logiquement rattachées Il est possible d'imbriquer des classes et interfaces dans des classes des interfaces dans des interfaces Les classes internes peuvent être héritées Une classe interne peut accéder à tous les membres même private la classe mère Une classe interne ne peut définir de membre statiques hors finaux Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 71 Classes internes Possibilité d'imbrication sur plusieurs niveaux Il est possible de distinguer les variables de même nom entre classe interne et externe classeExterne.this.nomVariable Une classe interne peut être statique Pour instancier une classe interne, il faut d'abord instancier la classe contenante ClasseContenante cc = new ClasseContenante(); ClasseContenante.ClasseInterne obj = cc.new ClasseInterne(); Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 72 Classes internes : exemple 1/3 class Formation { String nom; String type; Etudiant [] tabEtu = new Etudiant[10]; private int index = 0; Formation() { nom = ""; type = "";} Formation (String nom, String type) { this.nom = nom; this.type = type;} int nbEtudiants() { return index; } void ajouteEtu(String nom, String prenom) { Etudiant e = new Etudiant(nom, prenom); e.ajoute(); } … public String toString() { String chaine = ""; for(int i=0; i<index; i++) chaine = chaine + tabEtu[i] + "\n"; return chaine; } Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 73 Classes internes : exemple …. 2/3 class Etudiant { String nom, prenom; Etudiant() {nom = ""; prenom = "";} Etudiant(String nom, String prenom) {this.nom = nom; this.prenom = prenom;} void ajoute() { if (index<10) { tabEtu[index] = this; // la classe interne a accès à tous les éléments index++; // de la classe conteneur, même privés } } public String toString() { String formation = Formation.this.nom; return (formation + " : " + nom + " " + prenom); } } } Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 74 Classes internes : exemple public class TestFormation { public static void main(String args[]) { Formation f = new Formation("L3_Info", "bac+3"); 3/3 %javac TestFormation.java %ls *.class Formation.class Formation$Etudiant.class TestFormation.class f.ajouteEtu("alain", "zouave"); f.ajouteEtu("ben", "yolta"); System.out.println(f); } } Formation.Etudiant e = f.new Etudiant("cloe", "xerty"); System.out.println(e); L3_Info : alain zouave L3_Info : ben yolta L3_Info : cloe xerty Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 75 Classes locales Une classe locale est définie dans une méthode Une classe locale accède aux membres de la classe contenante Une classe locale ne peut accéder qu'aux membres de type final de la méthode englobante Une classe locale dans une méthode statique ne peut accéder qu'aux membres statiques de la classe contenante Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 76 Classes locales : exemple int division(int a, final int b) { class Verif { boolean divOk(){return (b!=0);} } Verif v = new Verif(); if(v.divOk()) return a/b; else return 0; } Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 77 Classes anonymes Il est possible de créer des classes anonymes héritant d’une classe ou implémentant une interface Pour un usage limité à 1 objet, … interface Professeur // soit une interface Professeur { String getName (); } … Professeur prof = new Professeur() // création dynamique d’une classe { // implémentant Professeur private String nom = "Adam"; // et création de l’objet prof de public String getName () { return nom; } // cette classe anonyme. }; System.out.println(prof.getName()); // utilisation classique de l’objet Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 78 Classes anonymes Une classe anonyme peut accéder aux membres de la classe contenante Une classe anonyme ne peut créer de nouveau constructeur, elle en hérite Possibilité de passer des paramètres au constructeur : void testAnonyme() { PersonneF p = new PersonneF("ab","cd", null){ public String toString() { return(nom.toUpperCase() +" " + prenom ); }}; System.out.println(p); } Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 79 Classes anonymes : Exemple import java.awt.*; import java.awt.event.*; public class TestFenetre { public static void main(String arg[]) { MaFenetre mf = new MaFenetre(); mf.ajoutGestionFenetre(); mf.show(); } } class MaFenetre extends Frame { MaFenetre() { this.setTitle("exemple de classe anonyme"); this.setBounds(10,10,400,50); } public void ajoutGestionFenetre() { MaGestionFenetre mgf = new MaGestionFenetre(); addWindowListener( new WindowAdapter() class MaGestionFenetre extends WindowAdapter { { public void public voidwindowClosing(WindowEvent windowClosing(WindowEventevt) evt) { { System.out.println("Fermeture de de la fenetre"); System.out.println("Fermeture la fenetre"); System.exit(0); System.exit(0); } } }); } } } Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 80 Les paquetages Un paquetage définit un espace nommé pour un groupe de classes Les paquetages sont organisés en hiérarchie Importation d'une classe ou de classes d'un paquetage : import import import import NomClasse; nomPaquetage.NomClasse; nomPaquetage1.nomPaquetage2.NomClasse; nomPaquetage.*; Le caractère * ne porte que sur les classes d'un paquetage, pas sur ses sous-paquetages Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 81 Les paquetages Définir un paquetage, ligne : package nomPaquetage; à placer en tête de fichier source Les fichiers d'un paquetage doivent se trouver dans le répertoire portant le nom du paquetage Possibilité de création automatique des répertoires pour les classes compilées : javac -d repDesClasses MonProg.java Attention à la portée des membres de classes, seuls les membres publiques sont accessibles entre paquetages Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 82 La classe Package La classe Package représente un paquetage Java Package paquet = Package.get("java.nio.channels"); Pour obtenir tous les packages en cours : Package[] paquets = Package.getPackages(); Quelques informations getImplementationTitle(); getSpecificationTitle(); getImplementationVendor(); getSpecificationVendor(); getImplementationVersion(); getSpecificationVersion(); ... Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 83 La classe Package Compatibilité : Vérifier si un paquetage est compatible avec une version prévue : if (paquet.isCompatibleWith("1.6.1")) { ....... } Sécurité : Vérifier si un paquetage est scellé : toutes les classes du paquetage proviennent du même fichier jar if (paquet.isSealed()){ ....... } Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 84 Introspection L'introspection permet de gérer dynamiquement des classes : Lister les membres Créer une instance d'une classe non importée La classe Class permet de créer des objets descripteurs de classe La JVM créé des objets Class pour chaque classe utilisée dans un programme Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 85 Introspection Récupérer le descripteur d'une classe chargée : javax.swing.JFrame fen = new javax.swing.JFrame(); Class classeJFrame = fen.getClass(); Charger une classe dynamiquement Class classeChargee = Class.forName("Fenetre"); Class classeChargee = Class.forName("javax.swing.JFrame"); Attention : la classe à charger doit être compilée et accessible : se trouver dans le classpath Récupérer le nom : getName() Possibilité de récupérer un tableau ! Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 86 Introspection Récupérer tous les éléments d'un descripteur de classe : Field[] getDeclaredFields(); Method[] getDeclaredMethods(); Constructor[] getDeclaredConstructors(); Récupérer les éléments publiques d'un descripteur de classe : Field[] getFields(); Method[] getMethods(); Constructor[] getConstructors(); Possibilité de récupérer les modificateurs Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 87 Introspection Création d'un objet et invocation d'une méthode : 1. définir un descripteur de classe 2. Récupérer les informations sur les constructeurs et membres 3. Choisir un constructeur du descripteur de classe 4. Créer une instance à partir du constructeur 5. Choisir une méthode du descripteur de classe 6. Invoquer la méthode sur l'instance créée Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 88 Introspection Création d'un tableau d'objets : Object tab = Array.newInstance(Class.forName("java.lang.String"), 20); int[] taille = {3,4,7}; Object cube = Array.newInstance(Class.forName("Personne"), taille); Ajout d'un élément : Array.set(tab, 0, "bonjour..."); Obtenir un élément: String mot = (String)Array.get(tab, 0); Obtenir la taille: int taille = Array.getLength(tab); Obtenir les tailles : int m=Array.getLength( Array.get(tab,0)); Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 89 Création dynamique d'instance: exemple import java.lang.reflect.Constructor; import java.lang.reflect.Method; public class TestClass { public static void main(String args[]) { try { Class c = Class.forName("Personne"); //recherche de la classe Personne Class typeParamCons[] = {String.class, String.class}; // recherche du constructeur avec Constructor ctor = c.getDeclaredConstructor(typeparamCons); // 2 paramètres String Object paramCons[] = {"benoit", "zed"}; // appel du constructeur avec Object personne = ctor.newInstance(paramCons); // 2 paramètres Method m = c.getMethod("affiche", null); // recherche de la méthode affiche m.invoke(personne, null); // appel de cette méthode } catch(Exception e) {System.out.println("Erreur de recherche de classe : " + e);} } } Emmanuel ADAM – Université de Valenciennes et du Hainaut Cambrésis 90