Les concepts de la Programmation Orientée Objet en Java Prawee Sriplakich [email protected] Ce support de cours est disponible sur http://www-src.lip6.fr/homepages/Prawee.Sriplakich/ mise a jour : 18/09/2006 1 Organisation 1. Introduction à la technologie Java 2. Concepts POO (basiques) 3. Environnements de Développement en Java. 4h 4. Concepts POO (avancés) 8h 5. Tableaux, collections et Map 6h 6. Manipulation des entrées/sorties 6h 7. Threads et synchronisation 6h 8. Manipulation des documents XML avec Java 6h 2 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Evaluation 50% Contrôle continu Les TPs suivants seront évalués : Travail en binôme Les critères d’évaluation sont : 4.3 : Réalisation des interfaces du mécanisme d'événements 6.1 : Flux de données et sérialisation 8.2 : Sérialisation et désétatisation d’objets en XML avec DOM L’explication sur le lancement du programme. La correction du programme. Le scénario de test couvrant toutes les fonctionnalités du programme La lisibilité du code et le commentaire sur le code. Le Java Doc et le document expliquant l’architecture globale du programme. 50% Examen (2h) Les documents du cours et des notes personnelles sont autorisés. 3 Programmation Orientée Objet, université Paris X, Prawee Sriplakich 1. Introduction à la technologie « Java » Java et une plateforme d'entreprise 4 Qu’est ce que « Java » ? Un langage de programmation interprété et compilé. Java code Byte code Byte code est interprété par JVM (Java Virtual Machine) Les applications Java s'exécutent sur quel type de machines ? Tous les types de matériels disposant d'une JVM 5 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Comment cela fonctionne t-il ? La JVM fournit un environnement d'exécution homogène (malgré l'hétérogénéité des OS/ matériels) 6 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Le « Java Development Kit » Java est un langage de programmation. Le « Java Development Kit » est une boite à outils : un compilateur java une machine virtuelle « JVM » un ensemble de bibliothèques (API) pour faciliter la programmation. Ex. Gestion d'E/S (ficher, réseaux), les collections (liste, ensemble) , IHM … 7 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Applets et applications Deux types de développements sont possibles : les Applets Un programme s'exécutant au sein d'un navigateur web. Téléchargeable en même temps qu'une page web Pas besoin d'installation Fonctionnalité limité (par mesure de sécurité) les applications Un programme standard s'exécutant sur la JVM. Moins de restriction (Les utilisateurs doivent faire confiance avant de l'exécuter) 8 Programmation Orientée Objet, université Paris X, Prawee Sriplakich La plate-forme entreprise « java » • Un grand nombre de bibliothèques ont été développées autour du langage Java • Elles offrent des fonctionnalités communes des applications d'entreprises Ex. Gestion de web, de base de données, de transactions etc. Simplicité du développement des applications complexes • La plateforme concurrence : .NET 9 Programmation Orientée Objet, université Paris X, Prawee Sriplakich 2. Concepts POO (basiques) Contenu: Class, Objet, Instanciation, Attribut, Méthode, Message (Invocation), Cycle de vie d'objets, Constructeur, Package 10 Class et objet Objet représente une entité dans le monde réel ou un élément du programme. Possède des états et des comportements Ex. un objet "Télévision" ses états = { allumé/éteint, chaîne courante, volume de son }, ses comportements = { allumer, changer de chaîne, changer de volume de son, éteindre } Class Un objet est une instance d'une classe la classe décrit l'objet. Description des états des attributs de la classe Description des comportements des méthodes de la classe. 11 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Exemple d'une class public class Television { // Etat private int volume; private int chaine; private boolean estAllume; // Comportements public void allumer() { … } public void eteindre() { … } public void augmenterVolume() { … } public void reduireVolume() { … } public void changerChaine(int _chaine) { … } } NB. Par convention, les noms des classes commencent par majuscule ceux des attributs/ méthodes commence par minuscule 12 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Instanciation Une classe peut être réutilisée pour instancier plusieurs objets Class Television boolean estAllume int volume int chaine Objets estAllume: true volume: 5 chaine: 1 estAllume: true volume: 6 chaine: 2 estAllume: false volume: 0 chaine: 0 13 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Question Définir une classe représentant des voitures. Les états des objets voiture doivent décrire Démarré ou non, position de boite de vitesse, vitesse… niveau d'essence, … Les comportements d'une voiture incluent: Démarrer, arrêter Changer boite de vitesse Accélérer, ralentir Tourner (selon le dégré spécifié) 14 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Solution public class voiture { private boolean estDemarre; private int posBoiteVitesse; private int vitesse; private int niveauEssence; public void demarrer() { … } public void arreter() { … } public void setPosBoiteVitesse(int pos) { … } public void accelerer() { … } public void ralentir() { … } public void tourner(int degre) { … } } 15 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Le typage d'attributs (et variables) Un attribut peut être typé : par une classe (Sa valeur est donc une référence vers un objet instance de cette classe) par un type primitif: Par un tableau de type primitif, ou de type classe boolean, short, int, long, float, double byte, char. Ex. int[] att1; Television[] att2; Un array est un objet NB. Une chaine de caractères est un objet instance de la class String 16 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Méthodes Le corps d'une méthode contient des instructions comme la programmation classique. Il peut accéder aux attributs de la classe Ex. public void changerChaine(int _chaine) { if(_chaine<0 || _chaine>108) { System.out.println("chaîne invalide "); } else { chaine = _chaine; // Accès à l'attribut chaine } } 17 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Attribut "this" Lorsque des variables locales portent les mêmes noms que les attributs de la classe, vous devez utiliser l'attribut "this" pour les distinguer. Ex. public void changerChaine(int chaine) { if(chaine<0 || chaine>108) { System.out.println("chaîne invalide "); } else { this.chaine = chaine; // this.chaine signifie l'attribut de la classe } } 18 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Interaction entre objets: messages Lors qu'un programme s'exécute, il comporte d'un ensemble d'objets et ces objets échangent des messages. Echange de messages = invocation d'une méthode Les paramètres sont envoyé dans le message. un telecommande une television changerDeChaine(3) 19 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Interaction entre objets : via référence entre objets Afin qu'un objet A puisse invoquer une méthode de l'objet B, A doit avoir une référence vers B. Ex. public class Telecommande { Television t; // une référence (un attribut) ……. public void boutonChaineAppuye(int boutonNo) { t.changerChaine(boutonNo); // invocation } } 20 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Question Définir une classe Messenger objet Messenger représente une messagerie d'un utilisateur. Il porte un identifiant, celui de l'utilisateur Il référence des objets Messenger auxquels il peut envoyer un message. On peut lui ajouter un contact. Il accepte un texte de l'utilisateur et le diffuse aux autres. Lors de la réception du texte diffusé, il l'affiche sur l'écran julien Un julie pierre 21 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Solution import java.util.Vector; public class Messenger { private String idUtilisateur; private Vector<Messenger> contacts = new Vector<Messenger>(); public void ajouterContact(Messenger contact) { contacts.add(contact) } public void diffuser(String texte) { for(int i=0; i< contacts.size(); i++) { Messenger contact = contacts.get(i); contact.recevoir(texte); } } public void recevoir(String texte) { System.out.println(idUtilisateur + " recoit: " + texte); } } 22 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Comment commencer le programme: Méthode main Un programme Java = un ensemble de classes. Une méthode main doit être définie dans une des classes. Elle doit avoir la signature: public static void main(String[] args) Le tableau <<args>> contient des paramètres passés par la commande d'exécution d'application Ex. java MyAppli p1 p2 p3 args est donc {"p1", "p2", "p3"} 23 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Un exemple de la classe main public class ClasseMain { public static void main(String[] args) { // creation d'objets Voiture v = new Voiture(); Personne p = new Personne(); // déclancher interaction entre objets p.conduire(v); } } En général, la méthode main sert à: Configurer le programme: (créer des objets initiaux du programme) Déclencher l'interaction entre ces objets 24 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Cycle de vie d'objets : création Pendant l'exécution du programme, les objets peuvent être crées et détruits de manière dynamique. La création d'un objet se fait par l'opérateur new suivi par le nom d'une classe Ex new Voiture() Voiture() est en effet une méthode spéciale, appelée le "constructeur de la classe". Le constructeur peut avoir des paramètres permettant de spécifier l'état initial de l'objet Ex. new File("document1.doc") // créer un objet représentant un ficher "document.doc". 25 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Exemple d'un constructeur public class Messenger { private String idUtilisateur; … public Messenger(String _idUtilisateur) { idUtilisateur = _idUtilisateur; } ……. } 26 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Cycle de vie d'objets : objets en cours d'utilisation L'objet en cours d'utilisation doit être référencé par une variable et un attribut. (sinon on ne pourrait pas l'utiliser !!) Un objet peut être référencé par plusieurs variables Ex. Voiture v = new Voiture(); // L'objet créé est référencé par la variable v. Ex. Voiture v1 = new Voiture(); Voiture v2 = v1; // v1 et v2 référencent le même objet. Pour utiliser l'objet, on invoque les méthodes de l'objet Ex. v1.demarrer(); // <<v2.demarrer()>> donnera le même effet car elle référence le même objet 27 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Cycle de vie d'objets : destruction Les objets non référencés sont automatiquement détruits Ex1. Voiture v = new Voiture(); v = null; // v ne référence plus l'objet, donc il sera détruit Ex2. public void m() { Voiture v = new Voiture(); } // v n'existe pas en dehors de la méthode, donc l'objet sera détruit à la fin d’exécution de la méthode 28 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Question L'objet référencé par v sera-il détruit à la fin exécution de m() ? public class VoitureManager { Voiture[] voitures = new Voiture[10]; ….. public void m() { Voiture v = new Voiture(); voitures[3] = v; v = null; } } 29 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Question Reprendre l'application Messenger, écrire la méthode main (dans une classe Main) servant à commencer le programme. La méthode main doit configurer 3 objets Messenger (pour Pierre, Julie, Julien) avec les liens entre eux. Elle déclenche l'application en demandant à Pierre de diffuser un texte. 30 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Solution public class Main { public static void main(String[] args) { Messenger pierre = new Messenger("pierre"); Messenger julie = new Messenger("julie"); Messenger julien = new Messenger("julien"); pierre.ajouterContact(julie); pierre.ajouterContact(julien); …. // similaire pour julie et julien pierre.diffuser("réunion demain à 10h"); } } 31 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Organisation d'application: package Une application peut contenir un grand nombre de classes. Hiérarchie de packages: Un package permet de grouper un ensemble de classes représentant un module d'application modularité Un package peut contenir non seulement des classes mais également des sous packages Ex. mon_appli.ihm.client est une hiérarchie de 3 packages Espace de nommage Differents packages peuvent avoir chacun une classe portant le même nom. Ex. La classe "Client" du package "com.ibm" est différente de la classe "Client" du package "com.microsoft" com.ibm.Client vs. com.microsoft.Client Eviter le conflit de noms lors de l'intégration de plusieurs modules d'une application. 32 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Organisation des classes dans les packages Chacune des classes est un fichier. Les fichiers doivent être placés dans le bon répertoire selon le package Dans chaque classe, on déclare le package au début du fichier Mot clé: package Ex. La classe ProductBrowser est dans le package mon_appli.ihm.client 33 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Spécification de classes dans les autres packages Dans le code d'une classe, une autre classe dans un autre package peut être spécifié avec la forme p1.p2….NomClass Cette forme est appelée <<nom qualifié>> d'une classe Ex. package mon_appli.ihm.client; public class ProductBrowser { mon_appli.bd.ProductSearcher ps; …. } 34 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Spécification de classes dans les autres packages avec <<import>> On peut éviter de répéter le nom qualifié plusieurs fois grâce à la déclaration <<import>> On peut importer une seule classe d'un package ou toutes ses classes Ex. : importer toutes les classes dans le package mon_appli.bd. package mon_appli.ihm.client; import mon_appli.bd.*; public class ProductBrowser { ProductSearcher ps; ProductSearcher ps2; …. } 35 Programmation Orientée Objet, université Paris X, Prawee Sriplakich 3. Environnements de Développement en Java Contenu: IDE, Complication, Exécution, Débuggage, Génération de documentation, Déploiement 36 Environnement classique et IDE Deux façons de développer: Environnement classique Complication/ execution par ligne de commande javac *.java : compiler des fichiers Java. java [nom de la classe main] : exécuter l'application IDE (Integrated Development Environment) Facilités Complication automatique Soulignements d'erreurs syntaxiques Débuggage avec interface graphique Ex. Eclipse 37 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Utilisation d'environnement classique Créer des classes avec votre éditeur préféré (Emac, Bloc-note) Mettre des classes dans les répertoires hiérarchiques selon leur package. Ouvrir la console de commande Positionner au répertoire racine (contenant les packages du plus haut niveau) Complier: javac [une liste des fichiers Java] Dans l'exemple de mon_appli, ce répertoire contient le répertoire mon_appli Ex: javac mon_appli/bd/*.java mon_appli/ihm/client/*.java mon_appli/ihm/admin/*.java Exécuter: java [le nom qualifié la classe main] Ex. java mon_appli.ihm.client.ProductBrowser NB. il faut positionner dans le bon répertoire (pour que la JVM puisse trouver les classes nécessaires) 38 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Utilisation de lDE Eclipse Créer un projet Créer des classes dans le répertoire source (par défaut c'est le répertoire du projet) File New class La complication se fait automatiquement lors de la sauvegarde des classes. File New projet Les erreurs syntaxiques sont soulignées ☺ Exécution Sélectionner la classe <<main>> Cliquer droit Run as Java Application 39 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Débuggage Le débuggage permet d'analyser le comportement du programme lors de son exécution Découvrir des erreurs. L'idée consiste à arrêter un programme à un moment donné et à examiner l'état des objets du programme. Debuggeur: un JVM qui offre le moyen d'arrêter l'exécution du programme à une ligne spécifiée (appelé point d'arrêt). Ex. jdb (IHM ligne de commande) usage: jdb [nom de la classe main] Eclipse (IHM graphique) usage: sélectionner la classe main, cliquer droite Debug as Java Application Différentes manières pour reprendre l'exécution Passer à la ligne suivante ("step over") Entrer dans le code de la méthode qui va être invoquée ("step into") Exécuter juste à la fin de la méthode et retourner à l'objet invoquant la méthode ("step return") Exécuter juste au point d'arrêt suivant ("resume") 40 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Débuggage avec Eclipse Contrôle de la reprise d'exécution Etat des objets et variable locales La pile d'invocation (qui appelle qui) Point d'arrêt 41 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Documentation (javadoc) La documentation facilite l'entretien de logiciel. Un exemple: la documentation des classes standard Java Réutiliser, corriger des erreurs, faire évoluer, etc. http://java.sun.com/j2se/1.4.2/docs/api/ On peut générer automatiquement le document à partir du code source ☺ Mais il faut mettre des commentaires sur le code source ! Ex. La classe String offre la méthode subString(…) permettant d'extraire une partie de la chaîne de caractères. 42 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Question : utilisation de la documentation Chercher la description de la classe Integer Chercher la classe Characters Quelle méthode permet de convertir une chaîne de caractères vers un nombre entier (int) ? Quelle méthode permet de tester si un caractère est minuscule ou majuscule Chercher la classe StringTokenizer Ecrire un programme permettant de couper une phrase en mots et les afficher (un mot par ligne). Conseil : méthodes hasMoreToken(), nextToken() String: "chercher une class" afficher chercher une class 43 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Documentation: ajouter des commentaires au code Entre /** Devant la déclaration d'une classe, d'une méthode, ou d'un attribut Mot clé: */ (et non /* */ ). @param, @return, @exception 44 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Documentation: la génération Avec ligne de commande javadoc [fichiers Java] Avec Eclipse Sélectionner le package Cliquer droite Export Javadoc Il est conseillé de rendre le javadoc généré dans le compte rendu du contrôle continu. 45 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Déploiement déploiement d'applications sous forme de fichiers d'archivage (JAR) Un fichier jar ressemble à un fichier ZIP. Il contient: Des classes compilées Du code source (optionnel) Des données nécessaires pour l'application (ex. images, données de configuration) Comment créer un fichier JAR Ligne de commande jar cvf [liste des fichiers] Eclipse Sélectionner le package Cliquer droite Export JAR file 46 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Déploiement: comment utiliser le fichier JAR ? Pour exécuter la classe main localisé dans un fichier jar, il faut dire à la JVM de chercher la classe dans ce fichier Utiliser le paramètre cp (classpath) Ex. java -cp messenger.jar poo.messenger.Main 47 Programmation Orientée Objet, université Paris X, Prawee Sriplakich TP 3.1 Création et exécution d'une application Créer l'application Messenger avec Eclipse 48 Programmation Orientée Objet, université Paris X, Prawee Sriplakich TP 3.2 Débuggage Débugger l'application Messenger avec Eclipse Mettre le point d'arrêt sur pierre.ajouterContact(julien); Examiner les 3 objets messenger Utiliser le contrôle de la reprise d'exécution pour entrer dans la classe Vector: Comment la classe Vector stocke t-elle les objets Messenger? A quelle index du tableau l'objet sera-il ajouté? Fixer un autre point d'arrêt à System.out.println(idUtilisateur + " recoit: " + texte); dans la méthode recevoir (…) Reprendre l'exécution jusqu'à ce point d'arrêt ("resume") Examiner la pile d'invocation Qu’ indique t-elle? Quel objet Messenger est-il en train de recevoir un texte ? Refaire "resume" et observer la différence dans la pile d'invocation Dans chaque étape, faire la capture-écran et répondre aux questions 49 Programmation Orientée Objet, université Paris X, Prawee Sriplakich TP 3.3 Java Doc Générer un javadoc de l'application Messenger avec Eclipse Ajouter des commentaires au code et régénérer le javadoc 50 Programmation Orientée Objet, université Paris X, Prawee Sriplakich 4. Concepts POO (avancés) Contenu: Héritage (Polymorphisme, Interface, Class abstraite, relation <<instance de>>, casting) Visibilité et encapsulation Attributs et Méthodes statiques Exception 51 Héritage Une héritage est une relation entre deux classes. Ex. Etudiant hérite de Personne: Object La classe étudiant et un sous-type (sous-classe) de la classe Personne (superclasse). Personne Syntaxe: mot clé "extends" public class Etudiant extends Personne { …} En Java, une classe ne peut pas hériter de plus d'une classe. Si l'héritage n'est pas déclaré, la classe hérite implicitement de java.lang.Object Etudiant une Enseignant hiérarchie de classes 52 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Sémantique d'héritage: attributs et méthodes La sous classe (ex. Etudiant) possède des attributs et des méthodes définis dans la superclasse (ex. Personne). Ex. public class Personne { String nom; public class Etudiant extends Personne { String noEtudiant; Etudiant(String _nom, _noEtudiant) { nom = _nom; noEtudiant = _noEtudiant; envoyerMail("[email protected]", "creation de dossier : " + nom); } public void envoyerMail( String adr, String message) { ….} } } 53 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Sémantique d'héritage: redéfinition (autrement dit spécialisation, <<overriding>>) La sous classe peut redéfinir les méthodes déjà existant dans la superclasse. Les méthodes redéfinies doivent garder la même signature. Ex. public class Personne { String nom; public void afficher() { System.out.println( "Personne : " + nom); } } public class Etudiant extends Personne { … public void afficher() { System.out.println( "Etudiant : " + nom + " no: " + noEtudiant); } } 54 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Etude de cas: redéfinition de la méthode equals(…) Comparaison par identité Deux variables de type objets sont égales si elles référencent le même objet (opérateur ==) Ex. Comparaison par le contenu String s1 = "hello"; String s2 = "hello"; String s3 = s1; System.out.println(s1 == s2); // false : pas le même objet System.out.println(s1 == s3); // true Deux objets sont égaux si leur contenu se ressemble. Personnalisation de comparaison La classe Object propose la méthode <<boolean equals(Object unAutre)>> pour comparer deux objets. Elle peut être redéfinie pour personnaliser la façon de comparaison. Les classes standard Java (ex. String, Integer) redéfibir equals(…) pour appliquer la comparaison par contenu. Ex. System.out.println(s1.equals(s2)); // true 55 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Exemple: redéfinition de la méthode equals(…) Object public Personne { String noSecu; … public boolean equals(Object autre) { if(autre instanceof Personne) { Personne p2 = (Personne) autre; if(noSecu.equals(p2.noSecu)) return true; } return false; } } equals(…) { // comparer par identité } Personne equals(…) { // comparer par contenu (no de sécu sociale) } String equals(…) { // comparer par contenu } 56 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Accès aux méthodes redéfinies dans la superclass Même si la sous classe redéfinit des méthodes de la superclasse, elle a le moyen d'accéder à ces méthodes en utilisant le mot clé <<super>>. public class A { public A(String s) { System.out.println("A : " + s); } public void m1() { System.out.println("A.m1"); } public void m2() { System.out.println("A.m2"); } } // main B b= new B("hello"); b.m1(); public class B extends A { public B(String s) { super(s); System.out.println("B : " + s); } public void m1() { super.m1(); m2(); // pas besoin de faire super.m2(); System.out.println("B.m1"); } } Résultat : A : hello B : hello A.m1 A.m2 B.m1 57 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Sémantique d'héritage: Substituabilité L'objet instance de la sous-classe peut se substituer là où l'objet instance de la superclasse est requis. Ex1. Personne p = new Etudiant(); Ex.2. Soit la méthode imprimerInfoPersonne() définit public void imprimerInfoPersonne(Personne p) { … } Il est possible de passer l'objet Etudiant comme le paramètre. Etudiant e = … ; inprimante.imprimerInfoPersonne(e); 58 Programmation Orientée Objet, université Paris X, Prawee Sriplakich getClass() et instanceof : Retrouver le type objet. Le problème: methode(Object param) { // param est-il un Etudiant? un Enseignant? ou autre?…. } La solution: getClass() : retrouver la classe d'objet // obtenir le nom de la classe de l'objet System.out.println(param.getClass().getName()); Instanceof : tester le type d'objet // supposant que param est instance de la classe Etudiant System.out.println(param instanceof Etudiant); // true System.out.println(param instanceof Personne); // true System.out.println(param instanceof Enseignant); // false 59 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Casting: convertir une variable vers un type plus spécifique Le problème : Object o = …. ; if(o instanceof Etudiant) { // o.afficher(); illégal // Maintenant on sait que o est de type Etudiant, // mais comment invoquer la méthode afficher() // de la classe Etudiant? } La solution: Casting. Etudiant e = (Etudiant) o; // les variable e et o référencent le même objet // mais elles sont de différents types. e.afficher(); 60 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Sémantique d'héritage: Polymorphisme Le polymorphisme est le fait qu'une classe peut avoir plusieurs sousclasses. Ex: Personne a comme sous-classes Etudiant et Enseignant. Par principe de substituabilité, le programme qui traite les objets Personnes n’a pas besoin de distinguer les objets Etudiant de ceux d'Enseignant public class Afficheur { Personne[] personnes; …. public void afficherToutePersonne() { for(int i=0; i<personnes.length; i++) { personnes[i].afficher(); // affichage d'un Etudiant // et celui d'un Enseignant peuvent être différents. } } } 61 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Interface: type abstrait Une interface est un type abstrait, censé être implémenté par des classes. Il ne contient que les méthodes sans corps. Ces méthodes sont à redéfinir dans les classes d'implémentation On ne peut pas créer une instance d'une interface mais on peut créer une instance d'une classe d'implémentation. <<Interface>> AdaptateurWifi envoyerDonner(..) recevoirDonner(..) AdaptateurWifiImpl1 envoyerDonner(..) { .. } recevoirDonner(..) { .. } AdaptateurWifiImpl2 envoyerDonner(…) {.. } recevoirDonner(...) { .. } 62 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Interface: héritage multiple Une classe peut hériter de plusieurs interfaces. Chaque interface représente un rôle d'une classe. Ex. un Lecteur CD-DVD a comme rôles LecteurCD et LecteurDVD <<Interface>> LecteurCD lirePiste(…) … <<Interface>> LecteurDVD selectionnerLanguage(); … LecteurCdDvdImpl lirePiste(…); selectionnerLanguage(...); …. 63 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Interface: syntaxe interface nom_de_l'interface [ extends noms d'autres interfaces ] { public void methode1(String param1) ; public int methode2(int param1, int param2) ; // autres méthodes … } Le mot clé "extends" permet à une interface d'hériter d'autres interfaces (une ou plusieurs) 64 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Implémentation d'une interface Une classe implémentant une interface doit redéfinir toutes les méthodes déclarées dans l'interface. public class LecteurCdDvdImpl implements LecteurCD, LecteurDVD { public void lirePiste(int noPiste) { …. // à faire } public void selectionnerLangue(String lang) { …. // à faire } } 65 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Les classes abstraites Une classe abstraite est incomplète Elle ne peut être utilisé telle quelle. Elle est censée être spécifiée par des sous classes. On ne peut pas créer une instance d'une classe abstraite. Une classe abstraite peut avoir des méthodes vides (à redéfinir par des sous-classes). 66 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Exemple d'une classe abstraite public abstract Feneitre { // attributs génériques pour tout type de fenêtres. int posX; int posX; int dimX; int dimY; // Les méthodes dont l'implémentation est générique // (pour tout type de fenêtres). public void deplacer() { … } public void redimensionner(int newDimX, int newDimY) { dimX = newDimX; dimY = newDimY; rafraichirContenu(); } // la méthode dont on ne connaît pas encore l'implémentation // (cela dépend de type de fenêtre). Ainsi on la laisse vide. public abstract rafraichirContenu(); } 67 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Visibilité: modificateur public/private Le modificateur public marque que les attributs/ méthodes d'une classe sont accessibles partout (dans les classes). Le modificateur private marque que les attributs/ méthodes d'une classe ne sont accessibles que dans cette classe. class C1 { public String a1; private String a2; public void m1(); private void m2(); } class C2 { void m3() { C1 c1 = new C1(); c1.a1 = "hello"; // OK // c1.a2 = "hello"; illégal c1.m1(); // OK // c1.m2(); illégal } } 68 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Visibilité : autre modificateurs de visibilité Les autres modificateurs sont: aucun modificateur (par défaut): les attributs/ méthodes sont accessibles par les classes du même package protected: les attributs/ méthodes sont accessibles par les classes du même package, et par les sous-classes de la classe courante. package p1; public class A { int a1; protected int a2; } public class B { // a1, a2 accessible } package p2; public class C { // a1, a2 non accessible } public class D extends A { // a1 non accessible // a2 accessible } 69 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Encapsulation : principe // pas d'encapsulation public class Date { public int jour; public int mois; public int annee; } // modification illégale Date d1 = new Date(); d1.jour = 30; d1.mois = 2; d1.annee = 2006; Principle d'encapsulation : Une classe devrait cacher des attributs et exposer ses méthodes au monde extérieur (aux autre classes) Protéger le contenu (les attributs) de la modification illégale Masquer les détails internes de la classe simplification 70 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Encapsulation: Protection du contenu public class Date { private int jour; private int mois; private int annee; public Date() { … // initialisé à la date aujourd'hui } public boolean setDate(int j, int m, int a) { if( estDateValide(j, m, a) ) { jour =j; moi=m; annee=a; return true; } else { return false; } } … } Seule la modification valide est permise 71 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Encapsulation: Masque de détails internes public class Image { // séquence d'octets au format propriétaire private byte[] donnees; public void chargerDeFichier(File ficher) { … // charger et convertir au format propriétaire } public void afficher() { …. // interpréter le format propriétaire. } } L'utilisateur n‘a pas besoin de connaître le format de données pour utiliser cette classe 72 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Membres statiques Le modificateur « static » peut s'appliquer à une méthode ou à un attribut d’une classe. L'élément statique est partagé par toutes les instances de la classe. Il est possible d’y accéder sans disposer d’une instance, mais directement par la classe. Ex : une méthode statique public class Calculatrice { public static int valeurAbsolue( int i ) { if(i < 0) return -1 * i; return i; } } // OK System.out.println( Calculatrice.valeurAbsolue(-25) ); // pas besoin de faire cela: Calculatrice c = new Calculatrice(); System.out.println( c.valeurAbsolue(-25) ); 73 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Membres statiques: Exemple public class Test { static int comptoir = 0; // initialiser lors du chargement de la classe int id; public Test() { id = comptoir; // utiliser le comptoir comme identifiant d'objet comptoir ++; //incrémenter le comptoir à chaque instanciation } public imprimerId() { System.out.println(id); } public static imprimerComptoir() { System.out.println(comptoir); } } public static void main(String[] args) { Test t1 = Test(); Test t2 = Test(); Test t3 = Test(); Test.imprimerComptoir(); // résultat? t1.imprimerId(); // résultat ? t2.imprimerId(); // résultat ? t3.imprimerId(); // résultat ? } Les méthodes statiques ne peuvent accéder qu’aux attributs statiques. 74 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Définition de constants Un constant peut être défini comme un attribut d’une classe, avec déclaration <<static>> (partagée par toutes les instances) et <<final>> (sa valeur est non modifiable) Par convention le nom d'un constant est tout en majuscules. public class MesConstants { public static final int LOAD = 0; public static final int SAVE = 0; public static final int MOVE = 2; } 75 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Exception Une exception représente un problème produit lors de l'exécution. Ex. NumberFormatException Integer.parseInt("vingt trois"); // un problème Une application robuste doit pouvoir gérer des exceptions. Scénario d'utilisation 1) Une exception créée et jetée (par un module d'appli. Ex, classe C1) 2) Une exception est saisie et traitée (par un autre module appli. Ex, classe C2) 76 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Exemple d'une exception public class FileLoader { public static byte[] load(String fileName) throws FileNotFoundException { if(…) { // si le fichier inexistant throw new FileNotFoundException(fileName); } … // chargement normal } } public class MonAppli { public static void main(String[] args) { String fileName = …; try { // tentative d'une opération susceptible de générer une exception byte[] contenu = FileLoader.load(fileName); print(contenu); } catch(FileNotFoundException e) { // traitement d'une exception System.out.println(e); } } } 77 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Définition des types d'exceptions On peut définir différents types d'exception. Ex: appli sécurisée: AuthentificationFailedException, InvalidUserNameException, InvalidePasswordException. Un type d'exception : une classe héritant de java.lang.Exception. On peut définir des attributs pour représenter l'info spécifique à un type d'exception public class AutentificationFailedException extends Exception { // information sur la date de la tentative de l'authentification et le nom de utilisateur java.util.Date date = new Date(); String userName; public AutentificationFailed(String userName) { this.userName = userName } } public class InvalidUserNameException extends AuthentificationFailedException { public InvalidUserNameException(String userName) { super(userName) } } 78 Programmation Orientée Objet, université Paris X, Prawee Sriplakich La déclaration <<throws>> La déclaration <<throws>> marque qu’une méthode est susceptible d’émettre une exception. La méthode peut produire une exception elle-même (avec opérateur <<throw>>) ou faire passer une exception produite par une autre méthode public class LoginManager { public void login(String userName, String password) throws AuthentificationFailedException, ConnectException { …. throw new InvalidUserNameException(userName); } } public class TransactionManager { public void doTransaction() throws AuthentificationFailedException, ConnectException { … loginManager.longin(userName, password); …. } } génératrice de l'exception Appelle faire passer l'exception 79 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Trace d'une exception La trace d'une exception informe sur l'origine de l'exception Facilité de débuggage Elle est une chaîne d'appels de méthodes MonAppli.main() TransactionManager.doTransaction() LoginManager.login throw new InvalidUserNameException(…) de la méthode génératrice de l'exception jusqu'à la méthode main Elle est stockée dans l'exception. Affichage de la trace : Chaîne d'appels : catch(Exception e) { e.printStackTrace(); } Affichage : InvalideUserNameException : jlopez at LoginManager.login (line 124) at TransactionManager.doTransaction (line 250) at MonAppli.main (linge 78) 80 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Le traitement d'exception try { … } catch(ExceptionType1 e) { … } catch(ExceptionType2 e) { … } 81 Programmation Orientée Objet, université Paris X, Prawee Sriplakich TP 4.1 : Héritage et redéfinition de méthode Implémenter une application avec des classes Personne, Etudiant, Enseignant et Afficheur. Un affichage d'un Etudiant et celui d'un Enseignant prennent les formes: Les classes Etudiant et Enseignant redéfinissent la méthode <<afficher()>> de la classe Personne. Etudiant : [nom] no : [noEtudiant] promo : [promo] Enseignant : [grade] [nom] Question Si on n’utilisait pas le concept de la redéfinition: Comment pourrait-on réaliser cette application (avec <<instanceof>>) ? Si on ajoute dans le futur d'autres sous-classes de Personne, y aurait-il un modificafication ? 82 Programmation Orientée Objet, université Paris X, Prawee Sriplakich TP 4.2 (1/5) : Manipulation des liens entre des objets Notre application gère le système de ficher. Elle se base sur: Un fichier a un nom et son contenu. On constate que le fichier et le répertoire ont des caractères communs Un répertoire a un nom. Un répertoire peut contenir des éléments qui sont soit des fichiers, soit des répertoires Classe Fichier Attribut représentant le contenu d'un répertoire Classe Répertoire Element Les deux portent un nom. Les 2 peut être contenus par un répertoire. Ainsi on crée la classe Element représentant ces caractères communs A faire: Définir en Java les classes Ficher, Répertoire et Element Fichier Attribut représentant le répertoire conteneur Repertoire 83 Programmation Orientée Objet, université Paris X, Prawee Sriplakich TP 4.2 (2/5) Définir les méthodes permettant de: Modifier le nom d'un fichier / répertoire Modifier le contenu d'un fichier Déplacer un fichier / répertoire Dans la classe Répertoire, écrire une méthode permettant d'afficher le contenu du répertoire récursivement. Ecrire une classe main pour tester cette appli. Créer une arborescence de fichier Afficher cette arborescence La modifier. Afficher le résultat 84 Programmation Orientée Objet, université Paris X, Prawee Sriplakich TP 4.2 (3/5) : Scénario de test move Projet Doc erreur attendue (boucle) rename Projet/Doc/Doc1.doc DocInterne erreur attendue (conflit de noms) move Projet/Doc Projet/src move Projet/src/Doc/Doc2.doc Projet/src rename Projet/src/Doc/Doc1.doc Doc2.doc move Projet/src/Doc/Doc2.doc src erreur attendue (conflit de noms) moveReplace Projet/src/Doc/Doc2.doc src écrasement attendu Affichage du répertoire (état initial) : [R] Projet [R] Projet/Doc [F] Projet/Doc/Doc1.doc : "contenu du Doc1.doc" [F] Projet/Doc/Doc2.doc : "contenu du Doc2.doc" [F] Projet/Doc/Doc3.doc : "contenu du Doc3.doc" [R] Projet/Doc/DocInterne [R] Projet/src [F] Projet/src/Class1.java: "class Class1 {}" … [R] Projet/bin [F] Projet/bin/Class1.class: "010000111" [R] = Répertoire [F] = fichier 85 Programmation Orientée Objet, université Paris X, Prawee Sriplakich TP 4.2 (4/4) IHM Créer la class IHM permettant à l'utilisateur d'interagir avec le système via les méthodes suivantes void move(String cheminSource, String cheminDestination, boolean canReplace); void rename(String chemin, String nouveauNom); 86 Programmation Orientée Objet, université Paris X, Prawee Sriplakich TP 4.2 (5/5) : Manipulation d'exception Ajouter la manipulation des exceptions dans le système de fichiers (TP précédent). Définir les types d'exceptions suivantes : InvalidName : l'utilisateur tente de nommer un fichier/ répertoire avec des caractères non valides ( / \ : < > ? * |) ou la longueur du nom excède 20 caractères. NameConflict : l'utilisateur tente de nommer un fichier avec un nom déjà pris par un des éléments dans le même répertoire OwnershipViolation : l'utilisateur tente de déplacer un répertoire dans un répertoire successeur. L'information que doivent porter les exceptions : InvalideName, NameConflict : le nom causant le problème OwnershipViolation : la tentative de déplacement (le répertoire à déplacer et le répertoire destinataire) Faire un scénario de test pour chaque cas d'exception 87 Programmation Orientée Objet, université Paris X, Prawee Sriplakich TP 4.3 (1/4) : Réalisation des interfaces du mécanisme d'événements Le mécanisme d'échange d'événements est très utilisé dans les applications d'aujourd'hui. Ce mécanisme se base sur 3 rôles: L’interface Sujet définit le rôle des objets qui peuvent émettre des événements. L’interface Observateur définit le rôle des objets désirant recevoir des événements L’interface Evenement définit les objets contenant chacun une information quelconque (selon le type d'événement) Le sujet offre une méthode pour inscrire des observateurs. L'observateur offre une méthode pour être notifiée lorsqu’un événement est émis. A faire: définir les interfaces Sujet, Observateur, Evenement 88 Programmation Orientée Objet, université Paris X, Prawee Sriplakich TP 4.3 (2/4) : Implémentation générique On souhaite implémenter cette application de manière générique avec la classe abstraite SujetAbstrait. Elle implémente le mécanisme pour maintenir la liste des Observateurs inscrits à ce sujet Elle offre la méthode (non abstraite) : void diffuserEvenement(Evenement ev); Cette méthode sera utilisée par les classes spécialistes pour diffuser des événements quelconques. 89 Programmation Orientée Objet, université Paris X, Prawee Sriplakich TP 4.3 (3/4) : Application sur le ebusiness Notre application est composée de Les classes FournisseurA, FournisseurB, FournisseurC représentent différents fournisseurs de produits dans le marché. Elles prennent le rôle de Sujet. Elles émettent des événements sur des offres de produits. Chaque fournisseur offre un différent produit. Les classes MagasinA et MagasinB ont le rôle d'Observateur. Elles souhaitent recevoir des offres de produits. Lorsqu’elles reçoivent des offres, elles affichent [MagasinB/ MagasinB] recu l'offre [nomProduit, prix, tempsLivraison] [accepte/ rejete] MagasinA accepte les produits moins chers que 100 euros. MagasinB accepte les produits livrables dans 7 jours maxi. La classe OffreProduit a le rôle d'événement. Elle contient l'information sur le nom du produit, le prix, le temps de livraison. A faire: Implémenter ces classes. Utiliser la classe SujetAbstrat 90 Programmation Orientée Objet, université Paris X, Prawee Sriplakich TP 4.3 (3/4) : Test Définir un scénario de diffusion d'offres Dans les classes FournisseurA, B, C définir la méthode : public void diffuserToutesOffres() { // ici on diffuse toutes les offres en répétant l'appel à la méthode // diffuserEvenement(…) hérité de la classe SujetAbstrait } Faire la classe main qui configure l'inscription des magasins auprès des fournisseurs et exécuter le scénario 91 Programmation Orientée Objet, université Paris X, Prawee Sriplakich 5. Tableaux, collections et Map 92 Tableaux Un tableau est une séquence d'éléments Séquence de données primitives Séquence de références vers objets Ex. int[], char[], byte[] Ex. Object[], Personne[] On crée un tableau l'avec l'opérateur <<new>> Ex. int[] tab1 = new int[10]; int dim = 20; Object[] tab2 = new Object[dim]; Pour un tableau d’objets, initialement ses éléments sont <<null>> Un tableau est lui-même un objet On accède aux éléments du tableau avec un index (entre 0 jusqu'à la dimension -1) On peut connaître la dimension du tableau par son attribut <<lenght>> 93 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Un tableau est un objet On peut affecter un tableau au variable de type java.lang.Object Object o = new Personne[20]; On peut découvrir le type du tableau System.out.println(o instanceof Personne[]); // résultat : true System.out.println(o.getClass().isArray()); // résultat : true System.out.prinln(o. getClass().getComponentType().getName()); // résultat : Personne 94 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Tableaux : redimension La dimension du tableau est fixée lors de la création de l'objet (new) Pour redimensionner, il faut : 1) Créer un nouveau tableau d'une nouvelle dimension 2) Copier les éléments de l'ancien tableau vers le nouveau Astuce: System.arraycopy( source, position, destination, position, nombreElements ); Ex. public static Object[] redimentionner(Object[] tab, int nouvelleDim) { Object nouveauTab = new Object[nouvelleDim]; int dimMin = (nouvelleDim> tab.length)? tab.length : nouvelleDim; System.arrayCopy(tab, 0, nouveauTab, 0, dimMin); } 95 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Un tableau de tableaux Quel est le tableau résultat de ce programme? int[ ][ ] tab2dim = new int[5][ ]; // création de tableau dimension 5 pour stocker des tableaux de <<int>> for(int i=0; i<tab2dim.length; i++) { tab2dim[i] = new int[i+1]; // creation d'un tableau de int for(int j=0; j< tab2dim[i].length; j++) { tab2dim[i][j] = j; } } 1 1 2 1 2 3 1 2 3 4 1 2 3 4 5 96 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Collections Une collection manipule un ensemble d'objets Elle possède des méthodes pour : Ajouter/supprimer un objet dans la collection Obtenir les objets dans la collection Plusieurs variations Une collection ordonnée une liste Une collection filtrant la duplication des membres un ensemble Un ensemble ne peut pas contenir le même objet plus d’une fois. 97 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Les collections prêtes à utiliser en Java Le package java.util offre des implémentations des collections prêtes à utiliser L’interface Collection définit les méthodes, par ex : boolean add(Object o) : ajouter un objet dans la collection int size() : consulter la taille de la collection iterator() : itérer dans tous les membres de la collection. Pendant l'itération, la collection ne doit pas être modifiée (pas ajout/suppression de membres) boolean contains(Object o) : tester si l'objet existe dans la collection. La comparaison d'objets se fait par la méthode equals(…). L’interface List : des collections ordonnées (listes). Elle définit des méthodes spécifiques aux listes, par ex : void add(int index, Object element) : ajouter un objet dans l'index specifié. public Object remove(int index) : retirer l'objet à l'index spécifié Les classes Vector, ArrayList sont des implémentations de List. La classe HashSet est une implémentation de Collection. Elle filtre la duplication de membres. Il n'existe pas deux objets o1 et o2 tels que <<o1.equals(o2)>> dans l'ensemble. 98 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Collection de données primitives On a vu que les membres de collections sont des objets et non des données primitives (int, char, double) Afin de mettre des données primitives dans une collection, on utilise la forme d'objets int class java.lang.Integer char class java.lang.Character double class java.lang.Double Ex. Collection c = new Vector(); c.add(new Integer(3)); c.add(new Integer(2)); System.out.println( c.contains(new Integer(3)); // true 99 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Copier une collection En général, les constructeurs des classes d'implémentation de collections (Vector, ArrayList, HashSet) prennent comme paramètre une collection source pour créer une copie. Ex. List v = new Vector(); v.add("a"); v.add("ab"); List copie = new Vector(v); copie.add("abc"); System.out.println(v); // résultat : [ a, ab ] System.out.pintln(copie); // résultat : [ a, ab, abc ] Il est possible d'utiliser un tel constructeur pour convertir entre plusieurs variations de collections un ensemble vers une liste : dans un ordre quelconque une liste vers un ensemble : la duplication est ignorée 100 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Conversion entre tableaux et collections Tableau vers collection utiliser la classe java.util.Arrays méthode : public static List asList(Object[] tab) Attention <<Returns a fixed-size list backed by the specified array. (Changes to the returned list "write through" to the array.)>> Afin d'obtenir une collection indépendante du tableau, créer une copie de la liste retournée par Arrays.asList(…) Ex.: Object[] tab = …; List l = new Vector(Arrays.asList(tab)); Collection vers tableau Collection c = …; Object[] tab = c.toArray(); String[] tab2 = (String[]) c.toArray(new String[c.length])); // obtenir un tableau d'un type spécifique 101 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Trier une liste La classe java.util.Collections propose les méthodes pour trier une collection. interface Comparable : static void sort(List list) : tirer une liste d'objet implémentant l'interface <<Comparable>> static void sort(List list, Comparator c) : trier une liste d'objet en utilisant un comparateur personnalisé propose la méthode : int compareTo(Object o); // retourne un nombre négatif, 0, nombre positif si inférieur de, égal à, supérieur Les objets basiques (Integer, String, Byte, Char, …) implémentent Comparable interface Comparator : propose la méthode : int compare(Object o1, Object o2) 102 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Paramétrage de la collection (Java 1.5) Java 1.5 permet au programmer de spécifier le type d'objets qui sont membres de la collection. Avantages Code plus lisible. Plus besoin de faire casting Ex. for(Iterator it = Détection d'erreurs lors de la complication (Ex. ajout d'objets de mauvais type dans la collection) // Java 1.5 List<String> v = new Vector<String>(); v.add("a"); v.add("b"); v.add(new Integer(3); // erreurs de compliation for(int i=0; i<v.size(); i++) { String s = v.get(i); v.set(i, "prefix_" + s ); } // Java 1.4 List v = new Vector(); v.add("a"); v.add("b"); v.add(new Integer(3); // pas d'erreurs de compliation for(int i=0; i<v.size(); i++) { String s = (String) v.get(i); // produire erreur d'exécution (ClassCastException Integer to String) v.set(i, "prefix_" + s ); } 103 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Map Un map (objet implémentant l'interface java.util.Map) représente un ensemble de couples <clé, valeur>. Les clés et valeurs peuvent être des objets de type quelconque. Il propose les méthodes : void put(Object key, Object value) : ajouter un couple <clé, valeur> dans le Map. S’il existe déjà un couple avec cette clé, le nouveau remplace l'ancien. Object get(Object key) : trouver la valeur associée à une clé. Object remove(Object key) : retirer le couple <clé, valeur> s'il existe. retourner la valeur retirée. Set keySet() : obtenir toutes les clés existant dans le map. Classes java.util.Hashtable, java.util.HashMap : implémentations de l'interface Map Classe java.util.Properties : une implémentation de Map dont les clés et les valeurs sont des String. 104 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Table de hachage (Hashtable) La table de hachage est une technique d'implémentation de Map Un tableau de grande taille est utilisé pour stocker les couples <clé, valeur> Le hachage de la clé permet de trouver l'index du tableau pour stocker le couple/ rechercher le couple. … stocker les couples dont leurs clés entre 0 – 99 … clés entre 100 - 199 Hachage : … clés entre 200 - 199 l'index de 5 0 l'index de 105 1 l'index de 145 1 l'index de 213 2 105 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Les objets clés doivent redéfinir la méthodes equals(..) et hashCode() boolean equals(Object uneAutreCle) int hashCode() Permet de tester si cette clé est égale à une autre clé. Permet de trouver l'index du tableau associé à cette clé. Contrat à respecter : si deux clés sont égales, elles doivent retourner le même index de hachage. Les classes standards (String, Integer, Double …) proposent déjà l'implémentation de ces méthodes. ☺ 106 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Exemple d'utilisation incorrecte de Hashtable Problème de programmation int[] key1 = { 1, 2, 3 }; int[] key2 = { 1, 2, 3 }; Map m = new Hashtable(); m.put(key1, "valeur de 123"); System.out.println( m.get(key1) ); //afficher <<valeur de 123>> System.out.println( m.get(key2) ); //afficher <<null>> m.put(key2, "nouvelle valeur de 123"); System.out.println( m.get(key1) ); //afficher <<valeur de 123>> System.out.println( m.get(key2) ); //afficher <<nouvelle valeur de 123>> System.out.println( key1.hashCode() == key2.hashCode()); // afficher <<false>> System.out.println( key1.equals(key2.hashCode()); // afficher <<false>> Les objets tableau ne proposent pas de bonne implémentation de equals(…) et hashCode() Ainsi key1 et key2 sont considérées comme inégales les couples <key1, …> et <key2, …> sont stockés dans deux index différents 107 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Redéfinition de la méthode equals(…) et hashCode() public class IntArray { // une classe enveloppant un tableau pour redéfinir les méthodes equals(..) et hashCode() private int[] tab; public IntArray(int[] tab) { this.tab = tab; } public boolean equals(Object o) { if(this==o) return true; if(! (o instanceof IntArray) ) return false; IntArray ia = (IntArray) o; if(tab[].length != ia.tab[].length) return false; for(int i=0; i<tab.length; i++) { if(tab[i] != ia.tab[i]) return false; } return true; } public int hashCode() { // Deux objets IntArray égaux retournent le même index. int somme = 0; for(int i=0; i<tab.length; i++) { somme=+tab[i]; } return somme; } } Programmation Orientée Objet, université Paris X, Prawee Sriplakich 108 Correction du problème int[] key1 = { 1, 2, 3 }; IntArray key1 = new IntArray(tab1); int[] key2 = { 1, 2, 3 }; InArray key2 = new IntArray(tab2); Map m = new Hashtable(); m.put(key1, "valeur de 123"); System.out.println( m.get(key1) ); //afficher <<valeur de 123>> System.out.println( m.get(key2) ); //afficher <<valeur de 123>> m.put(key2, "nouvelle valeur de 123"); System.out.println( m.get(key1) ); //afficher <<nouvelle valeur de 123>> System.out.println( m.get(key2) ); //afficher <<nouvelle valeur de 123>> System.out.println( key1.hashCode() == key2.hashCode()); // afficher <<true>> System.out.println( key1.equals(key2.hashCode()); // afficher <<true>> 109 Programmation Orientée Objet, université Paris X, Prawee Sriplakich TP 5.1 : Manipulation de tableaux Implémenter un programme cherchant un Objet dans un tableau méthode : int chercher(Object s, Object[] tab) retourner l'index si trouvé (sinon retourner -1) Tester ce programme avec cette méthode main : public static void main(String args) { Object[] tab = { "a", null, "ab", null, '"abc", "abcd" }; // initialisation d'un tableau System.out.println( chercher("ab", tab) ); System.out.println( chercher("xyz", tab) ); } 110 Programmation Orientée Objet, université Paris X, Prawee Sriplakich TP 5.2 (1/1) : Manipulation de listes Ecrire un programme permettant d'inverser l'ordre des membres d'une liste, sans modifier la liste originale Ecrire un programme permettant d'inverser une liste en modifiant la liste originale public List inverser(List org) public void inverserModif(List org) Ecrire un programme permettant de filtrer des membres de collections (de type Integer) qui sont inférieur à 0. public Collection filtrer(Collection intCollection) 111 Programmation Orientée Objet, université Paris X, Prawee Sriplakich TP 5.2 (1/2) : Manipulation de listes On propose l'interface Filtre permettant de définir un filtre personnalisé : Ecrire un programme permettant de filtrer une collection avec un filtre personnalisé public void Collection filtre(Collection c, Filtre f) Ecrire une classe d'implémentation de filtre (classe FiltreIntPair) pour filtrer des objets de type Integer public interface Filtre { public boolean estFiltre(Object o); // vrai si l'objet est à filtrer } Les nombres impairs sont filtrés Ecrire un programme prenant en arguments de ligne de commande une liste à filtrer Ex. java poo.tp5_3.MainClass 2 4 6 13 15 17 20 Astuce: en Eclipse, on spécifie les arguments de ligne de commande avec le menu Run Run l'onglet Arguments 112 Programmation Orientée Objet, université Paris X, Prawee Sriplakich TP 5.3 : Map multivalué Créer un map permettant d’associer une clé à plusieurs valeurs. Le principe consiste à utiliser le map <<normal>> associant une clé à une liste de valeurs. Implémenter la classe MultivalueMap public class MultivalueMap { Map<Object, List> map = new Hashtable<Object, List>(); // un map normal public void put(Object key, Object value) { … } public List get(Object key) { …} public List remove(Object key) { … } // supprimer toutes les valeurs associées à la clé et retourner les valeurs supprimées. public boolean remove(Object key, Object value) { … } // supprimer une seul valeur retourner vrai si la valeur a existé (et donc a été supprimée) } Est-ce que la modification de la liste retournée par la méthode get(…) affecte les données stockées dans le map? Proposer l'implémentation de get(..) qui empêche cela. Appliquer ce map pour stocker l'info sur les étudiants et leurs cours. Ex : put ("000123", "Systèmes I" ) : étudiant no 000123 prend le cours "Systèmes I" put ("000123", "OOP") : cet étudiant prend également le cours OOP put ("000124", "Anglais I" ) Ajouter la méthode affichant tous les couples du map sous forme d'une table. L'affichage doit respecter l'ordre descendant des numéros d'étudiants. 113 Programmation Orientée Objet, université Paris X, Prawee Sriplakich TP 5.4 (1/2) : Map de données les plus récemment utilisées Créer la classe <<CacheMap>> proposant les comportements suivants: Elle a une capacité de stockage limitée (à configurer lors de l'instanciation de la classe). Elle ne peut stocker que N couples. Lors qu'elle atteint sa capacité et que le programmeur tente d’ajouter un nouveau couple, elle supprime le couple le moins récemment utilisée (LRU: Least Recently Used). Pour identifier le couple LRU, elle maintient le classement de ces clés selon l’ordre d’accès (via put/get) CacheMap hérite de la classe Hashtable et redéfinit certaines de ses méthodes. 114 Programmation Orientée Objet, université Paris X, Prawee Sriplakich TP 5.4 (2/2) : Scénario de teste public static void main(String[] args) { CacheMap m = new CacheMap(1000) ; // capacité 1000 for(int i=0; i<10000; i++) { m.put(new Integer(i), new Integer(i * 2)); m.get(34); } System.out.println("la Map est de taille : " + m.size() ) ; // attendu : 1000 System.out.println("la valeur de 9956 est : " + m.get(new Integer(9956)); // attendu : 2 fois 9956 System.out.println("la valeur de 35 est : " + m.get(new Integer(35)); // attendu : null System.out.println("la valeur de 34 est : " + m.get(new Integer(34)); // attendu : 2 fois 34. } 115 Programmation Orientée Objet, université Paris X, Prawee Sriplakich 6. Manipulation des Entrées/ sorties flux et fichiers 116 Les entrées-sorties Le package « java.io » permet de gérer la manipulation d’entrées / sorties. Les entrées et les sorties sont des flux de données flux entrants : le programme peut lire les données. flux sortants : le programme peut y émettre des données. Source de données Un flux connecte un programme avec une sources de données Ex. écran/clavier, fichiers, connexion TCP/TP, Web Web Programme fichier 117 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Flux abstraits Abstraction Classe abstraites Permet au programme de lire/écrire des données de différentes sources de données de la même manière. Ex. On peut utiliser le même code pour lire des fichiers et des pages web. java.io.InputStream/ java.io.OutputStream : flux entrant/ sortant pour données brutes (octets) java.io.Reader/ java.io.Writer : flux entrant/ sortant pour données textes uni codes (16 bits) Exception java.io.IOException : représente des problèmes de la connexion de flux Dépendant des sources dé données : Fichiers, Web 118 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Flux d'octets InputStream propose les méthodes: int read() : lire un octet (retourné en int), -1 si le flux est terminé. int read(byte buf[]) : lire une séquence d'octets et la mettre dans buf, retourner un nombre d'octets lus (entre 0 et buf.length), -1 si le flux est terminé. close() : fermer le flux, libérer des ressources associées. OutputStream propose les méthodes: void write(int b) : écrire un octet (représenté avec int) dans le flux void write(byte buf[]) : écrire une séquence d'octets dans le flux. flush() : Si la mémoire tampon est utilisée, envoyer toutes les données de la mémoire tampon vers la destination. close() : terminer l'écriture sur la source de données. 119 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Flux de caractères Reader propose les méthodes: int read() : lire un caractère (retourné en int), -1 si le flux est terminé. int read(char buf[]) : lire une séquence de caractères et la mettre dans buf, Retourner un nombre de caractères lus (entre 0 et buf.length), -1 si le flux est terminé. close() : comme InputStream Writer propose les méthodes: void write(int c) : écrire un caractère (représenté avec int) dans le flux void write(char buf[]) : écrire une séquence de caractères dans le flux. flush() : comme OutputStream close() : comme OutputStream 120 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Flux concrets les classes abstraites InputStream/ OutputStream et Reader/ Writer sont à spécialiser pour représenter des flux concrets Exemple de flux d'octets FileInput(Output)Stream : lire/ écrire des fichiers ByteArrayInput(Output)Stream : lire/ écrire des octets dans un tableau via les méthodes de InputStream/ OutputStream ObjectInput(Output)Stream : lire et écrire des objets dans un flux quelconque (fichiers, réseaux) Exemples de flux de caractères FileReader(Writer) : lire/ écrire des fichiers textes StringReader(Writer) : lire/ écrire des caractères dans un String via les méthodes de Read/ Writer. 121 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Exemple : lecture/écriture de fichers import java.io.*; public class Copy { public static void main(String[] args) throws IOException { FileReader in = new FileReader("c:/source.txt"); FileWriter out = new FileWriter("c:/destination.txt"); int c; while ((c = in.read()) != -1) { out.write(c); } in.close(); // déverrouiller (lecture seule) le fichier out.close(); // écrire les données de la mémoire tampon vers le fichier et le fermer } } 122 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Lecture bloquante / non bloquante La lecture de données du flux peut engendrer un délai Ex. Congestion de réseaux. Le programme peut effectuer la lecture de deux manières Bloquante : le programme attend jusqu'à ce que les données soient disponibles InputStream.read(), Reader.read() : le programme ne sort de ces méthodes que quand un octet / caractère est prêt à retourner Non bloquante : le programme obtient uniquement les données actuellement disponibles InputStream.read(byte[] buf), Reader.read(char[] buf) : Si les données ne sont pas encore disponibles, alors la méthode retourne 0 comme le nombres d'octets/ caractères lus. 123 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Emballage (wrapping) de flux Certains types de flux peuvent emballer un autre flux. Ex. BufferedInput(Output)Stream, BufferedReader(Writer) propose la gestion de mémoire tampon. Augmenter la performance Le programme lire/ écrire des données sur la mémoire tampon. Ces données sont transférées de /vers le flux emballé. Les classes de flux qui peuvent emballer proposent un constructeur prenant comme paramètre le flux à emballer Ex. InputStream input = …; // flux entrant à emballer BufferedInputStream in = new BufferedInputStream(input); OutputStream output = …; // flux sortant à emballer BufferedOutputStream in = new BufferedOutputStream(output); 124 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Flux de connexion de réseaux Lecture d'une URL java.net.URL url = new URL("http://www.yahoo.com"); InputStream in = url.openStream(); Flux TCP/TP java.net.Socket socket = new Socket(" www.yahoo.com", 80); InputStream in = socket.getInputStream(); OutputStream out = socket.getOutputStream(); 125 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Manipulation de flux de caractères entrants La classe java.io.BufferdReader propose une méthode pratique pour lire chaque ligne de texte d'un flux emballé (InputStream). Ex. InputStream in = new FileInputStream("c:/note.txt") BufferedReader br = new BufferReader(in); String ligne = br.readLine(); Pour analyser la ligne lue, utiliser la classe java.util.StringTokenizer Ex. StringTokenizer st = new StringTokenizer(ligne); while(st.hasMoreToken()) { String t = st.nextToken(); System.out.println(t); } 126 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Manipulation de flux de caractères sortants La classe java.io.PrintWriter propose des méthodes pratiques pour écrire différents types d'information sous forme textuelle vers un flux emballé (OutputStream). Ex. print(int i), print(boolean b), print(String s), print(Object o) …. println(int i), println(boolean b), println(String s), println(Object o)…. Pour transformer un objet vers du texte [print(Object o)], la méthode toString() de l'objet est invoquée. La classe de l'objet peut fournir l'implémentation de toString() pour proposer la représentation textuelle de l'objet. Ex. Personne { String nom; … public String toString() { return "Personne : " + nom; } } OutputStream out = … ; PrintWriter w = new PrintWriter(out); Personne[] tab = …; w.println("Les membres de l'équipe") for(int i=0; i<tab.length; i++) { w.println(tab[i]); } 127 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Les flux d’entrée et de sortie standard Le flux d’entrée standard : System.in (instance de InputStream) Par défaut, la source de donnée est le clavier Flux standard de sortie (instance de PrintWriter): System.out : le flux sortant qui, par défaut, s’affiche à l’écran System.err : le flux sortant pour les erreurs (qui, par défaut, s’affiche également à l’écran ) 128 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Connexion de deux modules de programme avec un tuyau (<<pipe>>) Un programme peut être divisé en plusieurs modules. Chaque module effectue une tache parallèle. Un tuyau permet la communication entre les modules. un module permet d'envoyer des données à un autre module par un flux. Le module producteur : envoie des données par PipeWriter ou PipeInputStream Le module consommateur : renvoie les données par PipeReader ou PipeInputStream Etablissement de connexion de modules PipedWriter pipeOut = new PipedWriter(); PipedReader pipeIn = new PipedReader(pipeOut); // pipeOut est utlisé par le producteur // pipeIn est utlisé par le concomateur Module producteur utilise PipeWriter ou PipeOutputStream Module consommateur utilise PipeReader ou PipeInputStream 129 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Sérialisation et reconstitution d'objets à travers un flux La classes ObjectInput(Output)Stream permettent de lire et écrire des objets du programme Cas d'utilisation Sauvegarder l'état du programme dans un ficher pour pourvoir recharger plus tard Envoyer des objets d'un programme à un autre programme. Elle propose les méthodes void writeObject(Object o) : écrire un objet vers le flux. L'écriture d'objet consiste à écrire l'état de l'objet (tous les attributs) Object readObject() : reconstituer l'objet qui a été écrit par writeObject(…). Les classes des objets <<sérialisable>> doivent implémenter l'interface java.io.Serializable. 130 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Exemple de la sérialisation d'objets // chargement d'un objet d'un fichier FileInputStream fin = new FileInputStream("c:/biblio.obj"); ObjectInputSteam oin = new ObjectInputStream(in)); Biblioteque biblio = oin.readObject(); // on peut naviguer vers des livres et des adhérents et exemplaires public class Livre implements Serializable { String nom; String auteur; List<Exemplaire> exemplaires; } public class Bibliotheque implements Serializable { List<Livre> livres; List<Adhérent> adherents; } public class Adhérent implements Serializable { String nom; } public class Exemplaire implements Serializable { int no; Adhérent emprunteur; // null signifie libre } 131 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Exemple: Flux de données compressées // From The Java Developers Almanac 1.4 // Files to include in the ZIP file String[] filenames = new String[]{"filename1", "filename2"}; // Create a buffer for reading the files byte[] buf = new byte[1024]; try { // Create the ZIP file ZipOutputStream out = new ZipOutputStream(new FileOutputStream("outfile.zip")); // Compress the files for (int i=0; i<filenames.length; i++) { FileInputStream in = new FileInputStream(filenames[i]); // Add ZIP entry to output stream. out.putNextEntry(new ZipEntry(filenames[i])); // Transfer bytes from the file to the ZIP file int len; while ((len = in.read(buf)) > 0) { out.write(buf, 0, len); } // Complete the entry out.closeEntry(); in.close(); } // Complete the ZIP file out.close(); } catch (IOException e) { } 132 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Manipulation de fichiers et répertoires La classe java.io.File représente des fichiers et des répertoires existants ou non (qui vont être créés). Elle propose des méthodes suivantes pour manipuler les fichiers des répertoires : File(String pathname), File(String parent, String child) boolean exists() boolean canRead(), boolean canWrite() boolean delete(), boolean renameTo( File dest ) boolean isDirectory(), boolean isFile(), long length() boolean mkdir() File getParentFile(), File[] listFiles() 133 Programmation Orientée Objet, université Paris X, Prawee Sriplakich TP 6.1 : Flux d'objets et sérialisation On souhaite créer une application permettant aux utilisateurs d'éditer l'information dans une bibliothèque. Elle accepte des commandes suivantes du clavier. créer livre [nom] [auteur] [nombreExemplaire] créer adhérent [nom] emprunter [adhérent] [livre] retourner [adhérent] [livre] [noExemplaire] sauvegarder [nomFichier] : sauvegarder l'info sur un fichier. charger [nomFichier] : charger l'info depuis un ficher. arrêter : arrêter l'application 134 Programmation Orientée Objet, université Paris X, Prawee Sriplakich TP 6.2 : Manipulation de fichiers et répertoires Créer une application qui ressemble à une console. Elle propose les commandes suivantes pour manipuler les fichiers et répertoires pwd, cd [chemin complet ou relatif], cd .. dir mkdir [nom de répertoire], rename [nom actuel] [nouveau nom] move [fichier/répertoire] [chemin du répertoire destinataire]. del [nom de ficher/répertoire]. copy [fichier source] [fichier cible] view [fichier] visualiser sur l'écran 135 Programmation Orientée Objet, université Paris X, Prawee Sriplakich 7. Threads et synchronisation La programmation concurrente, synchronisation, wait et notify. Problèmes producteurconsommateur, lecteur-écrivain 136 Thread Un programme multithreads peut exécuter plusieurs activités en parallèle. Ex. Application de téléchargement : plusieurs threads téléchargent des fichiers en parallèle. Un thread suit une séquence d'instructions 137 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Exemple : téléchargement parallèle Thread A : charger un fichier : "A.zip" while(p<100.00) { [charger un bloc de données] [afficher : fileName chargé p% ] } [afficher : fileName chargement complet ] Thead B : charger un fichier : "B.zip" Ecran : A.zip chargé 3% B.zip chargé 8% A.zip chargé 5% B.zip chargé 13% ….. while(p<100.00) { [charger un bloc de données] [afficher : fileName chargé p% ] } [afficher : fileName chargement complet ] 138 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Définir ce que font des threads Les classes héritant de java.lang.Thread ou implémentant l'interface java.lang.Runable spécifient le code que doivent exécuter des threads. redéfinir la méthode run() Un objet instance d'une telle classe représente un thread Thread A : charger A.zip public class MonThread extends Thread { String fileName; public void run() { // redéfinition // le code } } Thread B : charger B.zip instanciation 139 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Deux façons de définir un thread Façon 1 : Créer une classe héritant de la classe java.lang.Thread Façon 2 : Créer une classe implémentant l'interface java.lang.Runnable 140 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Lancement de threads Instanciation d'une classe définissant le thread. Si la classe est définie de la façon 1 (Thread) t.start(); Si la classe est définie de la facon 2 (Runable) MonThread t = new MonThread("A.zip", "Thread A"); Le constructeur est utile pour passer des données qui seront manipulées par le thread Ex. passer le nom du fichier à charger. Créer un thread enveloppe et appeler start() Thread enveloppe= new Thread(t, "Thread A"); enveloppe.start(); La méthode run() que vous avez définie sera exécutée par le système en activité parallèle. N'appelez pas vous même la méthode run() ! : Cela ne créera pas le parallélisme. 141 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Exemple : lancement de thread chargeur de fichiers public class MonThread extends Thread { String fileName; public MonThread(String fileName, String threadName) { super(threadName); this.fileName = fileName; } public void run() { … } public static void main(String[] args) { MonThread tA = new MonThread("A.zip", "Thread A"); MonThread tB = new MonThread("B.zip", "Thread B"); tA.start(); tB.start(); } } 142 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Définir une tache périodique Exemple d'une tache périodique En général, une tache périodique épouse un comportement comme suit : Vérification de l'arrivée de nouveaux mails while(activated) { // faire quelque chose try { Thread.sleep(60000); // 60 secondes } catch(InterruptedException e) { } } La méthode sleep(..) permet au thread courrant d'arrêter l'exécution pendant un temps spécifié (en milliseconde) 143 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Synchronisation : le problème Quel problème peut se poser si plusieurs threads accèdent aux même données (objets) de manière concurrente? write(…) donnée (fichier) Thread A read() Thread B public File { public byte read() { …} public void write(byte[] b) { … } } 144 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Synchronisation : définition de section critique La section critique est une section où un seul thread peut entrer à chaque moment Ex. Le corps des méthodes read(), write(…) Deux approches pour définir la section critique Façon 1 : Mettre le mot clé <<synchronized>> devant la méthode Façon 2 : Utiliser le block : synchronized(object) { …. } // façon 1 public File { public synchronized byte read() { …} public synchronized void write( byte[] b) { … } } // façon 2 // A chaque fois de lire un fichier f synchronized(f) { f.read(); } 145 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Synchronisation : Exemple Trois threads tentent à exécuter les sections critiques d'un même objet en même temps un seul thread peut y entrer à chaque moment Thread 1 Thread 2 objet : f Thread 3 f.write(…); f.read(…); f.write(…) entrer dans la méthode bloqué bloqué exécuter la méthode bloqué bloqué finir la méthode entrer dans la méthode bloqué exécuter la méthode bloqué finir la méthode entrer dans la méthode exécuter méthode finir la méthode temps 146 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Coordination entre threads : Exemple de producteur-consommateur On présente ici une appli multi-thread qui a besoin de la coordination Cette appli est composée de: Des threads "producteur" qui produisent des données et les mettent dans une file de messages. Des threads "consommateur" qui prennent les données de la file. Cette appli nécessite la coordination suivante : Les producteurs et les consommateurs ne doivent pas accéder à la file en même temps (section critique) Quand la file est pleine : Les producteurs doivent attendre jusqu'à ce qu'une place dans la file est libérée. Quand la file est vide : Les consommateurs doivent attendre jusqu'à ce qu'une donnée est produite dans la file. Producteurs File de messages Consommateurs 147 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Moniteur d'accès Un moniteur d'accès propose des méthodes pour accéder à la file de manière contrôlée. Ces méthodes peuvent bloquer tant que les données ne sont pas prêtes pour y accéder. public class Moniteur { private List file = new Vector(); // file de messages. public synchronized void Moniteur(int capacity) { … } // créer un moteur pour une file d'attente de capacité spécifiée public synchronized void put(Object o) { … } // déposer une donnée. bloquer si la file est pleine. public synchronized Object take() { … } // prendre une donnée. bloquer si la file est vide } // producteur while(…) { moniteur.put(o); } // consommateur while(…) { System.out.println( moniteur.take() ); } 148 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Les méthodes wait(), notify(), notifyAll() Le moniteur d'accès a une responsabilité de bloquer/ débloquer les threads Les producteurs Les consommateurs Quand la file est vide : Bloquer Quand il existent des données dans la file : Débloquer. Le moniteur d'accès contrôle le blocage/ déblocage grâce aux méthodes : void wait() throws InterruptedException : Suspendre (bloquer) le thread courrant Quand le file est pleine : Bloquer Quand il existent des places libres : Bébloquer Lors que le thread est suspendu, il laisse les autres threads entrer dans la section critique void notify() : Réveiller (débloquer) un des threads qui ont été suspendus void notifyAll() : Réveiller tous les threads qui ont été suspendus Ces méthodes sont proposées par tous les objets Java (java.lang.Object) ☺ 149 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Implémentation du Moniteur d'accès public class MoniteurProdCons { private List file = new Vector(); private int cap; public MoniteurProdCons(int capacity) { this.cap = capacity; } public synchronized void put(Object o) { while(file.size()==cap) { // tant que la file est pleine try { wait(); } catch(InterruptedException e){ } } file.add(o); notifyAll(); // notifier les consommateurs de la production d'une donnée } public synchronized Object take() { while(file.size()==0) { // tant que la file est vide try { wait(); } catch(InterruptedException e){ } } Object o = file.remove(0); notifyAll(); // notifier les producteurs de la libération d'une place dans la file return o; } } 150 Programmation Orientée Objet, université Paris X, Prawee Sriplakich MoniteurProdCons: Illustration Cons1 Cons2 Prod1 print( m.take()); Entrer dans la section critique La file est vide, donc le thread est suspendu print( m.take() ); Entrer dans la section critique La file est vide, donc le thread est suspendu m.put(o1); Entrer dans la section critique La file devient { o1 }, Les threads suspendus sont notifiés Finir la méthode Réveiller Réveiller Rentrer dans la section critique Attendre de rentrer dans la section critique L'objet o1 est retirer de la file et affiché, la file devient vide Finir la méthode temps Rentrer dans la section critique La file est encore vide, donc le thread est suspendu à nouveau Programmation Orientée Objet, université Paris X, Prawee Sriplakich 151 Exemple de lecteur-écrivain L'appli lecteur-écrivain est un autre exemple de la coordination entre les threads. Elle est composée de Un ensemble de threads qui peuvent lire et écrire des données. Des lectures concurrentes sont permises Une écriture est exclusive d'autres lectures et écritures. Lecteur 1 Ecrivain 1 byte[1000] tableau Lecteur 2 Ecrivain 2 152 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Moniteur d'accès lecture-écriture public class MoniteurTableau { public synchronized void acquireReadLock() { … } // demander le droit de lecture, bloquer si le tableau est en écriture par un autre thread. public synchronized void acquireWriteLock() { … } // demander le droit d'écriture, bloquer si le tableau est en lecture/écriture par d'autres threads public synchronized void releaseReadLock() { … } // indiquer la fin de lecture public synchronized void releaseWriteLock() { …} // indiquer la fin d'écriture public byte read(int index) { … } public void write(int index, byte b) { … } } // lecteur Moniteur m = …; m.acquireReadLock(); for(int i=0, i<1000; i++ ) { byte b = m.read(i); … } m.releaseReadLock(); // écrivain Moniteur m = …; m.acquireWriteLock(); for(int i=0, i<1000; i++) { m.write(i, (byte)2); } m.releaseWriteLock(); 153 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Implémentation du moniteur public class MoniteurTableau { Set lecteurs = new HashSet(); // la liste des lecteurs en cours Thread ecrivain = null; // l'écrivain en cours public synchronized void acquireReadLock() { // attendre jusqu'à ce que le tableau ne soit pas en écriture par un autre thread while(ecrivain !=null) { try { wait(); } catch(InterruptedException e){ } } lecteurs.add(Thread.currentThread()); // inscrire un nouveau lecteur dans la liste } public synchronized void acquireWriteLock() { // attendre jusqu'à ce que le tableau ne soit ni en lecture ni en écriture par les autres threads while(ecrivain!=null || ! lecteurs.isEmpty() ) { try { wait(); } catch(InterruptedException e){ } } ecrivain = Thread.currentThread(); // inscrire l'écrivain en cours } public synchronized void releaseReadLock() { lecteurs.remove(Thread.currentThread() ); // enlever ce lecteur de la liste notifyAll(); // notifier les écrivains en attente } public synchronized void releaseWriteLock() { ecrivain=null; // indiquer qu'il n'existe plus d'écrivain en cours. notifyAll(); // notifier les lecteurs/ écrivains en attente } … // implémentation des méthodes read(…), write(…) } 154 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Sémaphore Un sémaphore est un moniteur d'accès qui maintient N jetons. Un thread peut prendre un jeton du sémaphore et puis le rendre au sémaphore Lors que aucun jeton n'est libre, un thread demandeur de jeton sera bloqué jusqu'à ce qu'un jeton soit libéré. La classe "sémaphore" ressemble à ceci: public class Semaphore { public Semaphore(int n) { … } // constructeur, créer un sémaphore de 'n' jetons. public void acquire() {… } // prendre un jeton, bloquer si aucun jeton n'est libre public void release() { … } // rendre un jeton, et réveiller les threads en attente } A vous d'essayer Ecrire le code de la classe Semaphore 155 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Package java.util.concurrent (Java 1.5) Java 1.5 propose maintenant les classes utilitaires pour manipuler la coordination entre les threads java.util.concurrent.ArrayBlockingQueue : similaire au moniteur producteur-comsommateur présenté Methodes : void put(Object o); Object take(); java.util.concurrent.locks.ReadWriteLock : similaire au moniteur lecture-écriture présenté. java.util.concurrent.Semaphore 156 Programmation Orientée Objet, université Paris X, Prawee Sriplakich TP 7.1 Producteur-consommateur Illustrer la coordiation de thread dans une application de producteurconsommateur Créer une file de messages de capacité 5. Créer 2 producteurs (P1, P2) et 2 consommateurs (C1, C2) P1 émet un par un des objets Integer {1, 3, 5, 7, 9 } dans la file, et P2, {2, 4, 6, 8, 10}. A chaque production, le producteur affiche le message : C1 et C2 prennent chacun 5 objets de la file. A chaque consommation, le consommateur affiche le message : [P1/P2] émet [objet] [C1/C2] reçu [objet] NB. P1 et P2 devraient être instances de la même classe <<Producteur>>. Comment peut-t-on configurer ces composants pour qu'ils puissent émettre différents objets? Expliquer le résultat affiché 157 Programmation Orientée Objet, université Paris X, Prawee Sriplakich TP 7.2 : Lecteur écrivain Illustrer la coordination de thread dans une application de lecteur-écrivain Compléter la classe MoniteurTableau. Créer le scénario de test avec 2 lecteurs (L1, L2) et 2 écrivains (E1, E2). Afin de mieux illustrer le parallélisme, on retarde la durée de la lecture/ écriture du tableau. C'est-à-dire que l’on fait dormir le thread pour une durée d'une milliseconde à chaque fois qu’un octet est lu ou écrit. Plus précisément, on ajoute l'instruction suivante entre la lecture/écriture de chaque octet : try { sleep(1); } catch(InterruptedException e) { } L1 et L2 affichent le message <<[L1/L2] read lock acquired>> après l'appel à acquireReadLock(), et affiche <<[L1/L2] releasing read lock>> avant l'appel à releaseReadLock(). E2 et E2 affichent les messages similaires Expliquer le résultat affiché. 158 Programmation Orientée Objet, université Paris X, Prawee Sriplakich TP 7.3 : Téléchargement de fichiers en parallèle Créer une application permettant de télécharger des fichiers spécifiés avec URLs en parallèle Utiliser la classe java.net.URL pour obtenir InputStream Utiliser la méthode lecture bloquante - int read() [] - pour lire une donnée octet par octet. Chaque block de 200 octets lus, afficher ce message : [nom de thread] : 200 octets lus. Créer un scénario de test avec 3 threads Question : Si on utilise un seul thread pour télécharger 3 fichiers, l'application sera-t-elle plus ou moins rapide? 159 Programmation Orientée Objet, université Paris X, Prawee Sriplakich 8. Manipulation des documents XML avec Java 160 XML (eXtensible Markup Language) Recommandation W3C Un document XML représente des données structurées sous forme d'un arbre. Ex. représentation d'un livre avec XML Interopérabilité <?xml version="1.0" encoding="UTF-16"?> <book> <booktitle> Learning Java and XML </booktitle> <chapter> <number> 1 </number> <title> Introduction </title> <content> ……. </content> </chapter> <chapter> …. </chapter> … </book> 161 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Les technologies XML Manipulation de base de documents XML : DOM, SAX Vérification du contenu de documents XML : DTD, Schéma XML Transformation de documents XML vers d'autres documents: XSLT Liaisons entre documents XML : XLink, XPointer Requête sur documents XML : XQuery Echange et traitement de documents XML dans les systèmes réparties : Web Services Applications spécifiques aux domaines : Quelques formats standards de documents XML SMIL (Synchronized Multimedia Integration Language) MathML (Mathematical Markup Language) ICE (Information and Content Exchange) … Plus d'info : http://www.w3c.org Programmation Orientée Objet, université Paris X, Prawee Sriplakich 162 Prolog XML Le prolog prend la forme : <?xml version="1.0" encoding="UTF-16"?> Il se localise au début du document XML Le document doit être encodé correctement d'après la déclaration dans le prolog Valeur par défaut : UTF-8 Ex. : Ces deux documents doivent être encodés différemment dans le flux d'octets ! <?xml version="1.0" encoding="UTF-16"?> <book> … </book> <?xml version="1.0" encoding="UTF-8"?> <book> … </book> 163 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Un document XML est un arbre des balises Les balises sont nommées. Les balises ouvrante et fermante Ex. <book> some content…</book> On peut y mettre des sous balises. Si entre les deux balises est vide on peut utiliser la forme courte Ex. <book>, <title>, <number> Ex. <book></book> <book/> Les balises doivent être bien formées (ouverture/ fermeture) Ex. <book> <name> </book> </name> Mal formé 164 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Choix entre sous balise et attributs Utilisation de sous balises <?xml version="1.0"?> <message> <to>[email protected]</to> <from>[email protected]</from> <subject>XML Is Really Cool </subject> <text> How many ways is XML cool? Let me count the ways... </text> </message> Utilisation des attributs <?xml version="1.0"?> <message to="[email protected]" from="[email protected]" subject="XML Is Really Cool"> <text> How many ways is XML cool? Let me count the ways... </text> </message> 165 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Des textes entre des balises <?xml version="1.0" encoding="ISO8859-1" ?> <message> (retourne de ligne) (tab) <to>[email protected]</to> (retour de ligne) (tab) <from>[email protected]</from> (retour de ligne) (tab) <subject>XML Is Really Cool</subject> (retour de ligne) (tab) <text> How many ways is XML cool? Let me count the ways... </text> (retour de ligne) </message> Lors de la manipulation de documents XML, on évite de traiter des textes non significatifs (retour de lignes, tab etc) En terminologie XML, ces textes sont appelés "PCDATA" (Parsed Character Data) Ils ne peuvent pas contenir ces caractères : < > ' " A replacer : < par &lt; > par &gt; & par &amp; ' par &apos; " par &quot; 166 Programmation Orientée Objet, université Paris X, Prawee Sriplakich D'autres caractères Caractères non parsé (CDATA) On peut mettre n'importe quel caractère entre <![CDATA[ et ]]> Des commentaires <!-- This is a comment --> <script> <![CDATA[ function matchwo(a,b) { if (a < b && a < 0) then { return 1 } else { return 0 } } ]]> </script> 167 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Espace de nom (<<namespace>>) XML Comment distinguer deux balises portant le même nom? xmlns:ns1="http://mydefinition/person" ….. <ns1:name>John Smith</ns1:name> xmlns:ns2="http://my-domain/map/street" ….. <ns2:name>Wall street</ns2:name> Un namespace est défini par un URI : person name : street name Solution: utiliser le namespace <name>John Smith</name> <name>Wall street</name> Ex. http://:mydefinition/person, http://my-domain/map/street Un namespace est référencé par un alias Ex. ns1, ns2 168 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Exemple d'un document XML avec des namespaces <f:table xmlns:f="http://www.w3schools.com/furniture"> <f:name>African Coffee Table</f:name> <f:width>80</f:width> <f:length>120</f:length> </f:table> 169 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Grammaire de documents XML <book> <booktitle> Learning Web Services </booktitle> <birthday>12-01-1982</birthday> <chapter> <number> 1 </number> <title> What are Web Services? </title> <content> ……. </content> </chapter> … </book> Est-ce correct? Besoin de définir quelles balises sont permises. 170 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Grammaire de documents XML : Deux approches DTD Simple Un DTD peut être mis au début du document XML Schéma XML Plus puissant, de plus en plus utilisé. Un schéma XML est lui-même un document XML. 171 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Un exemple de DTD <?xml version="1.0"?> <!DOCTYPE note [ <!ELEMENT note (to,from,heading,body)> <!ELEMENT to (#PCDATA)> <!ELEMENT from (#PCDATA)> <!ELEMENT heading (#PCDATA)> <!ELEMENT body (#PCDATA)> ]> <note> <to>Tove</to> <from>Jani</from> <heading>Reminder</heading> <body>Don't forget me this weekend!</body> </note> 172 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Un exemple de Schéma XML <?xml version="1.0"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.w3schools.com" xmlns="http://www.w3schools.com" elementFormDefault="qualified"> <xsd:element name="note" type="notetype"/> <xsd:complexType name="notetype"> <xsd:sequence> <xsd:element name="to" type="xsd:string"/> <xsd:element name="from" type="xsd:string"/> <xsd:element name="heading" type="xsd:string"/> <xsd:element name="body" type="xsd:string"/> </xsd:sequence> </xsd:complexType> </xsd:schema> 173 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Manipulation de documents XML en Java Manipulation de documents XML Analyser le contenu des documents. Construire un document W3C propose deux APIs pour manipuler les documents Java Vérification du contenu, extraction d'information DOM (Document Object Model) SAX (Simple API for XML) Ces APIs ont été portées sur la plateforme Java Packages: org.xml.sax, org.w3c.dom 174 Programmation Orientée Objet, université Paris X, Prawee Sriplakich 8.1. SAX (Simple API for XML) 175 SAX Programmation dirigée par événements Evènements : start A start H start G … end A Document XML Traitement Parseur 176 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Exemple d'événements générés <?xml version="1.0"?> <book> <booktitle> Learning Java and XML </booktitle> <chapter> <number> 1 </number> <title> Introduction </title> <content> ……. </content> </chapter> <chapter> …. </chapter> … </book> start book, start booktitle, start chapter, start number, end number, start title, end title, start content, … end content, end chapter, …. end book 177 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Le parseur : org.xml.sax.XMLReader Méthodes pour configurer les traiteurs d'événement. void setContentHandler(ContentHandler handler) Méthode pour commencer le parcours du document parse(org.xml.sax.InputSource input) throws IOException, SAXException void L'objet InputSource peut être construit en enveloppant l'objet java.io.InputStream ou java.io.Reader. 178 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Interface org.xml.sax.ContentHandler On implémente l'interface ContentHandler pour traitement des éléments. Les méthodes suivantes seront appelées lors du parcours d'un document XML : Début et fin du document Début et fin de chaque élement void startElement(String namespaceURI, String localName, String fullName, Attributes atts) void endElement(String namespaceURI, String localName, String fullName) Détection du texte entre des balises void startDocument() void endDocument() void characters(char[] ch, int start, int length) … 179 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Interface org.xml.sax.ContentHandler (en plus de détails) startElement(…) et endElement(…) : Les significations de ses paramètres String namespaceURI : URI de l'espace de nom (ex. http://www.w3schools.com/furniture) String localName : le nom de la balise sans l'espace de nom (ex. table, name, width, length) String fullName : le nom complet (ex. f:table, f:name, f:width, f:length) Attributes atts [pour startElement(…)] : une liste des attributs de cette élément. On peut consulter cette liste via l'API de org.xml.sax.Attributes void characters(char[] ch, int start, int length) Les caractères sont localisés dans le tableau <<ch>>. Ils commencent à l'index <<start>> et ont pour longueur <<length>> Pour obtenir un String, on peut faire : String s = new String(ch, start, length); // on obtient "African Coffee Table", "80", ou "20" <f:table xmlns:f="http://www.w3schools.com/furniture"> <f:name>African Coffee Table</f:name> <f:width>80</f:width> <f:length>120</f:length> </f:table> 180 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Localisation des balises dans le document Le parseur passe l'objet Locator au ContentHandler. Lors que le ContentHandler reçoit un événement, il demande la localisation de la balise concernée au Locator 1: setDocumentLocator(locator) Parseur 2: startElement(…) Locator ContentHandler 3: getLineNumber() getConsumeNumer() 181 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Traitement d'erreurs XMLReader génère des erreurs lors du parcours du document methode void parse(org.xml.sax.InputSource input) throws IOException, SAXException Les erreurs peuvent être : Caractères non valides trouvés. Document XML mal formé (manque de balises ouvrant / fermant) Problèmes de E/S (IOException) Si les erreurs sont détectées, le parseur arrête le parcours du document et jette une exception. On peut afficher plus de détails d'erreurs comme suit } catch (SAXParseException spe) { System.out.println("\n** Parsing error" + ", line " + spe.getLineNumber() + ", uri " + spe.getSystemId()); System.out.println(" " + spe.getMessage() ); } catch (Exception e) { e.printStackTrace(); } 182 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Arrêt du parcours Arrêter le parcours d'un document XML, c'est utile dans les cas suivants : Les méthodes de ContentHandler offrent le moyen de jeter des exceptions On trouve une erreur, donc inutile de parser plus loin On trouve une information qu'on recherche dans le document, puis on souhaite arrêter le parcours. startElement(..), endElement(..), characters(..) throws SAXException. Lors que ContentHandler jette une exception, le parseur va arrêter le parcours du document et ensuite jeter une exception par la méthode parse(…) parse(...) Appli évènement Parseur SAXException ContentHandler SAXException 183 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Spécification de l'implémentation du parseur SAX L'API SAX est un ensemble d'interfaces. Elle peut donc avoir différentes implémentations. La classe org.xml.sax.helpers.XMLReaderFactory permet d’instancier un objet XMLReader avec une classe d’implémentation particulaire static XMLReader createXMLReader() : utiliser la propriété Systeme "org.xml.sax.driver" pour identifier l'implémentation. static XMLReader createXMLReader(String className) : créer une instance de la classe d'implémentation spécifiée. NB. Les propriétés système peuvent être configurées de 2 façons Ligne de commande (lors de lancement de l'appli) Ajouter –D[propriété]=[valeur] En exécution java.lang.System.setProperty("property1", "valeur1"); 184 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Récapitulatif : étape à suivre Créer une XMLReader XMLReader r= XMLReaderFactory.createXMLReader(); Spécifier le ContentHandler r.setContentHandler(monContentHandler()); Parser r.parse(inputStream); 185 Programmation Orientée Objet, université Paris X, Prawee Sriplakich TP 8.1 SAX Yahoo! fournit un service de recherche web retournant le résultat en format XML Exemple d'une requête au Yahoo! Web Search http://api.search.yahoo.com/WebSearchService/V1/webSearch?appid=Yaho oDemo&query=java+xml&results=100 Examiner le document XML retourné. Ecrire un programme permettant de filtrer les résultats plus récents d'une date spécifiée (D'après la balise <ModificationDate>). Afficher toute info sur les résultats retenus. NB. La date de modification est représentée par une long Modifier le programme précédent pour qu'il arrête le parcours du fichier une fois que 10 résultats sont retenus. 186 Programmation Orientée Objet, université Paris X, Prawee Sriplakich 8.2. DOM (Document Object Model) 187 DOM L'API DOM permet de naviguer dans un arbre XML et le modifier Navigation Modification Document XML Construction d'un arbre Document XML Programme Sérialisation 188 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Les nœuds dans un arbre XML Document : le nœud racine. Il contient un fils unique de type Element Element : une balise XML Il peut contenir des Eléments fils, des Attributs et des Textes Attr : des attributs dans les Eléments Text, CDATASection, Comment : des nœuds représentant PCDATA, CDATA, et des commentaires, localisés entre des balises Les Texts peuvent être des retours de ligne, des tabs. Node : un nœud générique Document, Element, Attr, Text, CDATASection, et Comment héritent de Node. 189 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Construction d'un arbre La class javax.xml.parsers.DocumentBuilder permet de construire un arbre. Un DocumentBuilder peut-etre obtenu par le factory Un arbre est accessible à partir de l'objet org.w3c.dom.Document DocumentBuilderFactory.newInstance().newDocumentBuil der() Le DocumentBuilder propose les méthodes : Document parse(InputStream in) : créer un arbre à partir du flux XML Document newDocument() : créer un arbre vide 190 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Navigation Document d = documentBuilder.parse(inputStream); // obtenir la balise racine. Element root = d.getDocumentElement(); // obtenir le nom de la balise root.getName() // obtenir des attributs dans une balise NamedNodeMap attMap = root.getAttributes(); for(int i=0; i<attMap.getLength(); i++) { Attr a = (Attr) attMap.item(i); System.out.println( a.getName() +" : " +a.getValue() ); } String value = root.getAttribute("att1") //Une autre façon // obtenir des fils (Element, Text, CDATASection ou Comment ) NodeList nodeList = root.getChildNodes(); for(int i=0; i< nodeList.getLength(); i++) { Node n = nodeList.item(i); if(n instanceof Element) { …. } // sinon n peut être instance de Text, CDATASection ou Comment } 191 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Navigation On peut également monter dans l'arbre Element parent = (Element) elem.getParentNode(); On peut naviguer d'un élément vers le Document Document doc = elem.getOwnerDocument(); On peut naviguer 192 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Modification d'un arbre // le document permet de créer des Element, Text, CDATASection, et commentaire Document doc = …; Element elem = doc.createElement("message"); Text text = doc.createTextNode("mon texte"); // ajouter ou supprimer un attribut dans une balise elem.setAttribute("attr1", "valeur1"); elem.removeAttribute("attr2"); // ajouter ou supprimer un fils (Element/Text/CDATASection/Comment) dans un Element elem1.appendChild(fils); elem1.insertBefore(nouveauFils, refFils); elem1.removeChild(fils); 193 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Exemple : construction d'un arbre Document doc = documentBuilder.newDocument(); Element message = doc.createElement("message"); message.appendChild(root); Element to = doc.createElement("to"); message.appendChild(to); Text toText = doc.createTextNode("[email protected]"); to.apprendChild(toText); Element from = doc.createElement("from"); message.appendChild("from"); …. 194 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Sérialisation d'un arbre La classe javax.xml.transform.Transformer permet d'écrire un arbre XML vers un texte. public static void write(Element root, OutputStream out) throws Exception { Transformer transformer = TransformerFactory.newInstance().newTransformer(); DOMSource domSource = new DOMSource(root); transformer.transform(domSource, new StreamResult(out)); } 195 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Spécification de l'implémentation de DOM Comme SAX, l'API DOM est un ensemble d'interfaces. Il peut donc avoir différentes implémentations. La classe javax.xml.parsers.DocumentBuilderFactory permet d’instancier un objet DocumentBuilder avec une classe d’implémentation particulaire. System.setProperty( "javax.xml.parsers.DocumentBuilderFactory ", "[une classe d'impléménation]"); DocumentBuilder builder = new DocumentBuilderFactory().newInstance(). newDocumentBuilder(); 196 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Récapitulatif : analyser un document XML Obtenir DocumentBuilder DocumentBuilder builder = DocumentBuilderFactory().newInstance().new DocumentBuilder(); Parser un document XML Document d = builder.parse(inputStream); Naviguer dans l'arbre 197 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Récapitulation : écriture d'un document XML Obtenir DocumentBuilder DocumentBuilder builder = DocumentBuilderFactory().newInstance().newDocum entBuilder(); Créer un arbre vide Document d = builder.newDocument(); Créer des fils et les mettre dans l'arbre Sérialiser l'arbre write(rootElement, outputStream); 198 Programmation Orientée Objet, université Paris X, Prawee Sriplakich Comparaison entre SAX et DOM SAX Traitement par événements : les traiteurs d'événements sont appelés par le parseur. Capable de traiter un très grand document : le document n'est pas gardé dans la mémoire en intégralité. ☺ Pas possible de revenir sur les éléments du passé. DOM Traitement par navigation : un arbre est d'abord construit. Ensuite, le programme y navigue. Pas optimal pour le grand document : le document doit être intégralement chargé dans la mémoire. Possible de naviguer dans tous les sens. ☺ 199 Programmation Orientée Objet, université Paris X, Prawee Sriplakich TP 8.2 DOM Modifier l'appli de bibliothèque (TP 6.1) pour supporter la sauvegarde et le chargement de données en format XML comme suit : <?xml version="1.0"?> <Bibliotheque> <Livre nom="…" auteur="…"> <Exemplaire no="1" emprunteur="adherent1" /> <Exemplaire no="2" /> </Livre> …. <Adherent id="adherent1" name="Jennifer Lopez" /> … </Bibliotheque> 200 Programmation Orientée Objet, université Paris X, Prawee Sriplakich