1 Chapitre III (~70 transparents) Compléments
2 Au sommaire de ce chapitre 1. Les fichiers Les classes utilitaires La généricité Autres API java, compilation JIT et archive jar
3 1 – Les fichiers
4 Les flux Java propose un ensemble de classes pour la gestion des E/S décrites dans le package java.io Java propose un ensemble de classes pour la gestion des E/S décrites dans le package java.io –les E/S sont implémentées par les flux (stream) Un flux est tuyau de transport séquentiel de données Un flux est tuyau de transport séquentiel de données Il existe un flux par type de données à transporter Il existe un flux par type de données à transporter
5 Les flux (suite) Un flux est unidirectionnel Un flux est unidirectionnel
6 Deux familles de flux Les flux de caractères (caractères sur 16 bits) Les flux de caractères (caractères sur 16 bits) –dans un flux texte les données sont stockées sous forme de caractères sur le disque, et non sous forme d’octets il y a donc une transformation qui est effectuée entre mémoire et disque il y a donc une transformation qui est effectuée entre mémoire et disque Les flux d'octets (informations binaires sur 8 bits) Les flux d'octets (informations binaires sur 8 bits) –dans un flux binaire aucune transformation n'est effectuée sur les octets échangés
7 Flux d’octets en entrée 3 Classes utilisées pour la communication lecture de fichiers octets par octets récupère des données provenant d'un flux de sortie (cf. PipedOutputStream) lit des données dans un tampon structuré sous forme d'un array Classe abstraite
8 Flux d’octets en entrée 4 Classes utilisées pour le traitement concaténation d'une énumération de plusieurs flux d'entrée en un seul flux d'entrée lecture d'une String (mais Sun déconseille son utilisation et préconise son remplacement par StringReader) lecture d'objets Java « lisibles » lit à partir d'un InputStream quelconque des données, en "filtrant" certaines données
9 Flux d’octets en sortie 3 Classes utilisées pour la communication écriture de fichiers octets par octets Envoi de données sur un flux d’entrée écrit des données dans un tampon structuré sous forme d'un array Classe abstraite
10 Flux d’octets en sortie 2 Classes utilisées pour le traitement écriture d'objets Java lisibles avec ObjectInputStream.writeObject() écrit à partir d'un OutputStream quelconque des données, en "filtrant" certaines données
11 Les classes des flux caractères La hiérarchie des classes relatives aux E/S de caractères comprend 2 classes abstraites La hiérarchie des classes relatives aux E/S de caractères comprend 2 classes abstraites – Abstract Reader Class : lecture sur les flots caractères – Abstract Writer Class : écriture sur les flots caractères
12 Les classes d'E/S A cela il faut rajouter aussi comme classes de base : A cela il faut rajouter aussi comme classes de base : – File : fichier – RandomAcessFile : accès aléatoires sur un fichier
13 Sérialisation-Désérialisation Parmi tous les mécanismes d'E/S proposés par Java, le plus intéressant est la sérialisation qui permet : Parmi tous les mécanismes d'E/S proposés par Java, le plus intéressant est la sérialisation qui permet : –de sauvegarder des objets dans un fichier –(désérialisation : restaurer des objets à partir d'un fichier) Deux classes du package java.io sont utilisées Deux classes du package java.io sont utilisées – ObjectOutputStream pour la sérialisation – ObjectInputStream pour la desérialisation flux binaires
14 La sérialisation Pour écrire le tampon dans le flux, on appelle la méthode writeObject() Pour écrire le tampon dans le flux, on appelle la méthode writeObject() –la classe de l'objet qui effectue la sérialisation doit être public (souvent, c’est le main ) –la classe de l'objet sérialisé doit implémenter l’interface Serializable Cette méthode appelle également la méthode writeObject() de chaque objet composite Cette méthode appelle également la méthode writeObject() de chaque objet composite –si leur classe implémente l'interface Serializable –et jusqu'à ce que tout ce qui compose l'objet soit écrit
15 Premier exemple FileOutputStream fos = new FileOutputStream("t.tmp"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeInt(12345);oos.writeObject("Today"); oos.writeObject(new Date()); oos.close();
16 Exemple : sérialisation d’un objet import java.io.*; public class SerializerPersonne { public static void main(String argv[]) { Personne unePersonne = new Personne("Dupond","Jean",175); Personne unePersonne = new Personne("Dupond","Jean",175); try { try { FileOutputStream fichier = new FileOutputStream("personne.ser"); FileOutputStream fichier = new FileOutputStream("personne.ser"); ObjectOutputStream oos = new ObjectOutputStream(fichier); ObjectOutputStream oos = new ObjectOutputStream(fichier); oos.writeObject(unePersonne); oos.writeObject(unePersonne); oos.flush(); // pour forcer le tampon à se vider dans le fichier oos.flush(); // pour forcer le tampon à se vider dans le fichier oos.close(); // on ferme le tampon pour terminer l ’ op é ration oos.close(); // on ferme le tampon pour terminer l ’ op é ration } catch (IOException e) { catch (IOException e) {e.printStackTrace();} } // de main() } Une exception de type IOException peut être levée si un problème intervient avec le fichier
17 Le fichier obtenu Après l'exécution de cet exemple, un fichier nommé « personne.ser » est créé Après l'exécution de cet exemple, un fichier nommé « personne.ser » est créé On peut visualiser son contenu mais surtout pas le modifier car sinon il serait corrompu On peut visualiser son contenu mais surtout pas le modifier car sinon il serait corrompu En effet, les données contenues dans ce fichier ne sont pas toutes au format caractères En effet, les données contenues dans ce fichier ne sont pas toutes au format caractères –Fichiers binaires : les valeurs numériques sont codées en binaire
18 L'interface Serializable Cette interface ne définit aucune méthode Cette interface ne définit aucune méthode –mais permet simplement de marquer une classe comme pouvant être sérialisée (cf. Cloneable ) Elle est définie dans java.io Elle est définie dans java.io Si l'on tente de sérialiser un objet qui n'implémente pas l'interface Serializable Si l'on tente de sérialiser un objet qui n'implémente pas l'interface Serializable –une exception NotSerializableException est levée
19 La dé-sérialisation Classe java.io.FileInputStream Classe java.io.FileInputStream –Un FileInputStream est un flux d’octets en entrée pour lire des données à partir d'un fichier – FileInputStream est une sous-classe de InputStream Classe java.io.ObjectInputStream Classe java.io.ObjectInputStream –Un ObjectInputStream est un tampon qui lit des données (en octets: type primitif et objets) à partir d’un InputStream
20 Processus de dé-sérialisation Il est un tout petit peu plus complexe… Il est un tout petit peu plus complexe… Pour remplir un tampon de lecture à partir d'un fichier, on appelle la méthode readObject() Pour remplir un tampon de lecture à partir d'un fichier, on appelle la méthode readObject() –cette méthode renvoie une référence sur Object –il faut donc effectuer un transtypage Si on ne connaît pas la classe d'appartenance d'un objet (parmi plusieurs possibles) Si on ne connaît pas la classe d'appartenance d'un objet (parmi plusieurs possibles) –on récupère la classe par les méthodes getName() et getClass() de la classe Class –exemple : if (monObjet.getClass().getName().equals(MaClasse)
21 Désérialisation du premier exemple FileInputStream fis = new FileInputStream("t.tmp"); ObjectInputStream ois = new ObjectInputStream(fis); int i = ois.readInt(); String today = (String) ois.readObject(); Date date = (Date) ois.readObject(); ois.close();
22 Ex. : dé-sérialiser une Personne public class DeSerializerPersonne { public static void main(String argv[]) { try { FileInputStream fichier = new FileInputStream("personne.ser"); ObjectInputStream ois = new ObjectInputStream(fichier); Personne someOne = (Personne) ois.readObject(); System.out.println("Personne : "); System.out.println("nom : "+ someOne.getNom()); System.out.println("prenom : "+ someOne.getPrenom()); System.out.println("taille : "+ someOne.getTaille()); } catch (java.io.IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } // de main() } ici on sait que l’objet lu est de type Personne
23 Ex. 2 : sérialisation d’un tableau import java.io.*; // illustration de la sérialisation class TestSerialisation { public static void main (String argv[ ]) { Compte[] tabcpt = new Compte [3]; // on crée un tableau de 3 comptes tabcpt[0] = new Compte("tartempion", 3500); tabcpt[1] = new Compte("dupond", 1000); tabcpt[2] = new Compte("martin", 7500); try { // sérialisation // ouverture du fichier String nomFic = "FCOMPTE.TMP"; // nom du fichier File f1 = new File(nomFic);// déclaration d'un fichier // définition d'un flot de sortie et écriture : FileOutputStream fs = new FileOutputStream(f1); ObjectOutputStream fsObj = new ObjectOutputStream(fs); fsObj.writeObject(tabcpt); // on écrit tout le tableau fsObj.close();// on ferme le flot
24 Exemple 2 : dé-sérialisation System.out.println("\n Lecture du fichier\n"); // définition d'un flot en lecture FileInputStream fe = new FileInputStream(f1); ObjectInputStream feObj = new ObjectInputStream(fe); // on lit le flot et on récupère dans un tableau Compte table[] = (Compte []) feObj.readObject(); // affichage des résultats for (int i=0; i < table.length; i++) { table[i].affiche(); System.out.println("\n"); } feObj.close();// on ferme le flot } catch (Exception e) { e.printStackTrace(); System.out.println("\n "+e.getMessage()+"\n "); } } // fin de TestSerialisation
25 Exemple 2 : la classe Compte // extrait de la classe Compte class Compte implements Serializable { private static int numeroAttribue = 0; // attributs de la classe private int numeroCompte; private String nomCompte; private float soldeCompte; Compte(String nom, float solde) { numeroCompte = ++numeroAttribue; nomCompte = new String (nom); soldeCompte = solde; } public void affiche(){ System.out.println(" - Numero...: "+numeroCompte); System.out.println(" - Nom......: "+nomCompte); System.out.println(" - Solde....: "+soldeCompte); }... } // fin de la classe Compte
26 A noter… La classe ObjectInputStream possède toutes les méthodes pour lire des données de type primitif : La classe ObjectInputStream possède toutes les méthodes pour lire des données de type primitif : –readInt(), readDouble(), readFloat... Lors de la déserialisation, le constructeur de l'objet n'est jamais utilisé Lors de la déserialisation, le constructeur de l'objet n'est jamais utilisé
27 Précisions sur les exceptions Une classe peut effectuer un traitement durant la sérialisation ou désérialisation en implémentant les méthodes suivantes : Une classe peut effectuer un traitement durant la sérialisation ou désérialisation en implémentant les méthodes suivantes : – private void writeObject (ObjectOutputStream stream) throws IOException; – private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException; ClassNotFoundException;
28 Exceptions possibles Si la classe a changé entre le moment où elle a été sérialisée et le moment où elle est déserialisée Si la classe a changé entre le moment où elle a été sérialisée et le moment où elle est déserialisée –L’exception qui est levée est : java.io.InvalidClassException Une exception de type streamCorruptedException peut être levée si le fichier a été corrompu Une exception de type streamCorruptedException peut être levée si le fichier a été corrompu –par exemple en le modifiant avec un éditeur
29 Exceptions possibles (suite) Au cours de la déserialisation : Au cours de la déserialisation : Une exception de type ClassNotFoundException peut être levée si l'objet est transtypé vers une classe qui n'existe plus ou pas au moment de l'exécution. –Par ex. si on renomme Personne.class
30 Précisions (suite) Lorsqu'un attribut d'une classe ne doit pas être sérialisé il faut le déclarer transient Lorsqu'un attribut d'une classe ne doit pas être sérialisé il faut le déclarer transient –Le contenu des attributs sont invisibles dans le flux dans lequel est sérialisé l'objet. –Il est ainsi possible pour toute personne ayant accès au flux de voir le contenu de chaque attribut même si ceux si sont private : –Ex. : private transient String codeSecret; –Attention lors de la déserialisation, les champs transient sont initialisé avec la valeur null ! Un attribut static n'est pas sérialisé Un attribut static n'est pas sérialisé Les sous-classes d'une classe sérialisable le sont également Les sous-classes d'une classe sérialisable le sont également
31 2 – Les classes utilitaires
32 Classes utilitaires Composants du package java.util fournis Composants du package java.util fournis –sous forme de classe –ou sous forme d'interface Quelques exemples Quelques exemples –classes conteneurs Vector, Stack, HashMap –classes outils Random, Date –interfaces Collection Iterator Observer
33 La classe Vector Cette classe définit un conteneur de type tableau dynamique Cette classe définit un conteneur de type tableau dynamique –il s'agit d'une collection d'objets de type quelconque –à laquelle on peut accéder soit par un index soit par un itérateur –la classe Vector implémente l'interface List ce qui permet de l'utiliser comme une liste –les instances stockées peuvent être des objets de classes différentes
34 Le vector est une liste abstraite public class Vector extends AbstractList implements List, RandomAccess, Cloneable, Serializable Object AbstractCollection Vector AbstractList
35 Vector() //crée un vecteur vide Vector() //crée un vecteur vide Vector(int capacitéInitiale ) Vector(int capacitéInitiale ) // crée un vecteur vide de capacité initialCapacité // crée un vecteur vide de capacité initialCapacité Vector(int capacitéInitiale, int incrémenteCap ) Vector(int capacitéInitiale, int incrémenteCap ) // crée un vecteur vide et un facteur d'accroissement spécifié // crée un vecteur vide et un facteur d'accroissement spécifié protected int capacityIncrement : attribut de Vector, = valeur avec laquelle la capacité du vector est automatiquement incrémentée lorsque la taille du vecteur dépasse sa capacité initiale protected int capacityIncrement : attribut de Vector, = valeur avec laquelle la capacité du vector est automatiquement incrémentée lorsque la taille du vecteur dépasse sa capacité initiale Permettre l’optimisation de la gestion mémoire (consulter la documentation java) (consulter la documentation java) Constructeurs de la classe Vector
36 Classe Vector Principales méthodes supportées: Principales méthodes supportées: –ajout, insertion, suppression, recherche, extraction d'un élément Insertion d'un élément boolean add(Object o) // ajoute l'élément à la fin du vecteur void add(int Index, Object element) // insère l'élément donné en position donnée Quelques méthodes de Vector
37 Quelques méthodes de la classe Vector Recherche - information Object get(int index) // renvoie l'élément situé à la position indiquée int indexOf(Object element) // recherche la première occurrence d'un élément- surcharge // nécessaire de la méthode equals / critère de recherche int size() // renvoie le nombre de composants du vecteur Suppression - Modification Object remove(int index) // supprime l'élément situé à la position indiquée boolean remove(Object o) // supprime la première occurrence de l'élément donné void clear() // supprime tous les éléments du vecteur
38 Conversion d'un vecteur en un tableau Object[] toArray() Object[] toArray(Object[]tab) Tri du conteneur 1. Spécifier que la classe des objets du conteneur implémente l'interface Comparable 2. Implémenter la méthode compareTo dans cette classe 3. Invoquer la méthode sort de la classe Collections Vector conteneur = new Vector(20,5); …. Collections.sort(conteneur); Vector conteneur = new Vector(20,5); …. Collections.sort(conteneur); Quelques méthodes de la classe Vector
39 Exemple Classe TestPersonnel // utilisation de la classe Vector // définition d'une instance de Vector de 20 éléments et dont // la capacité est augmentée de 5 si débordement Vector conteneur = new Vector(20,5); // on ajoute 2 instances de la hiérarchie Personnel conteneur.add(new Employe("dupond","poste 2091",20.50f,160)); conteneur.add(new Directeur("BigBoss","top secret",85000, f)); // variable temporaire Personnel temp = new Employe("toto","--",20.50f,160); // insère l'objet temp en deuxième position dans le conteneur conteneur.add(1,temp); // affichage du contenu du vecteur for (int i=0; i<conteneur.size();i++) { System.out.println("\n\n Caracteristiques du salarie : "); System.out.println((Personnel)conteneur.get(i)); } Transtypage obligatoire type Object
40 Exemple :utilisation d’un itérateur // définition d'un itérateur Iterator it = conteneur.iterator(); // affichage du contenu du vecteur par l'iterateur while (it.hasNext()) { System.out.println("\n\n Caracteristiques du salarie:"); System.out.println((Personnel)it.next()); } // conversion du vecteur en un tableau de Personnel Personnel tabSalarie[] = new Personnel[conteneur.size()]; tabSalarie = (Personnel[])conteneur.toArray(tabSalarie); // affichage du contenu du tableau for (int i=0;i<3;i++) { System.out.println("\nCaracteristiques du salarie : "); System.out.println(tabSalarie[i]); }
41Exemples dans la classe Personnel // supprimer la référence sur le deuxième élément conteneur.remove(1); // ou bien si on veut garder une référence sur l'élément supprimé Personnel recup = (Personnel) conteneur.remove(1); System.out.println("\n\n Caracteristiques du salarie supprime: " + recup); // pour rechercher l'occurrence d'un élément il faut // avoir surchargé la méthode equals() pour le type de // l'élément : ici, dans la hiérarchie Personnel, le // critère choisi est le nom: boolean equals(Personnel p) { return nomPers.equals(p.getNom()); }
42 Exemple (fin) // on peut aussi rechercher un objet dans le conteneur par la méthode indexOf: i = conteneur.indexOf(temp); System.out.println("\n\n le salarie recherche est à la position: "+i);
43Exemples dans la classe Personnel // pour trier le conteneur il faut d'abord spécifier que // la classe Personnel implémente l'interface Comparable // et il faut définir ensuite la méthode compareTo() // de la classe Personnel // ici, on veut trier par le numéro de téléphone : public int compareTo(Object p) { return numTel.compareTo(((Personnel)p).numTel); } // on effectue le tri du conteneur en invoquant la méthode sort de la classe Collections //ATTENTION ne pas confondre avec l'interface Collection (sans s) !!! Collections.sort(conteneur); // pour vider totalement le conteneur conteneur.clear();
44 Interface Comparable Tous les objets qui doivent définir un ordre utilisé par le tri d'une collection Tous les objets qui doivent définir un ordre utilisé par le tri d'une collection –doivent implémenter cette interface. Cette interface = une seule méthode : int compareTo(Object) Cette interface = une seule méthode : int compareTo(Object) Cette méthode doit renvoyer : Cette méthode doit renvoyer : - une valeur entière négative si l'objet courant est inférieur à l'objet fourni - une valeur entière positive si l'objet courant est supérieur à l'objet fourni - une valeur nulle si l'objet courant est égal à l'objet fourni
45 Les classes wrappers des types de base = classes fournissant les méthodes utiles pour la manipulations de ces types (Integer, Short, Double, etc), mais aussi String et Date implémentent l’interface Comparable Les classes wrappers des types de base = classes fournissant les méthodes utiles pour la manipulations de ces types (Integer, Short, Double, etc), mais aussi String et Date implémentent l’interface Comparable –On peut donc comparer ces objets Rappel : Classe Integer ≠ type int Rappel : Classe Integer ≠ type int –Integer.parseInt("-240"))transforme la chaîne "-240" en valeur entière -240 Interface Comparable
46 Les collections Les collections en Java stockent toujours des références sur les objets contenus dans la collection et non les objets eux mêmes Les collections en Java stockent toujours des références sur les objets contenus dans la collection et non les objets eux mêmes –Ce sont obligatoirement des objets qui doivent être ajoutés dans une collection – Il n'est pas possible de stocker directement des types primitifs : il faut obligatoirement encapsuler ces données dans des wrappers.
47 Interfaces Java pour les collections Les interfaces à utiliser par des objets qui gèrent des collections sont : Collection : interface qui est implementée par la plupart des objets qui gèrent des collections. Collection : interface qui est implementée par la plupart des objets qui gèrent des collections. Map : interface qui définie des méthodes pour des objets qui gèrent des collections sous la forme clé/valeur Map : interface qui définie des méthodes pour des objets qui gèrent des collections sous la forme clé/valeur Set : interface pour des objets qui n'autorisent pas la gestion des doublons dans l'ensemble Set : interface pour des objets qui n'autorisent pas la gestion des doublons dans l'ensemble List : interface pour des objets qui autorisent la gestion des doublons et un accès direct à un élément List : interface pour des objets qui autorisent la gestion des doublons et un accès direct à un élément SortedSet : interface qui étend l'interface Set et permet d'ordonner l'ensemble SortedSet : interface qui étend l'interface Set et permet d'ordonner l'ensemble SortedMap : interface qui étend l'interface Map et permet d'ordonner l'ensemble SortedMap : interface qui étend l'interface Map et permet d'ordonner l'ensemble
48 Collections personnalisées Le package Java pour les collections fournit aussi plusieurs classes abstraites Le package Java pour les collections fournit aussi plusieurs classes abstraites –qui proposent une implémentation partielle d'une interface pour pouvoir créer une collection personnalisée : – AbstractCollection, AbstractList, AbstractMap, AbstractSequentialList et AbstractSet
49 Quelques méthodes de l’Interface Collection boolean add(Object) // ajoute l'élément fourni en paramètre à la collection. La valeur de retour indique si la collection a été mise à jour boolean add(Object) // ajoute l'élément fourni en paramètre à la collection. La valeur de retour indique si la collection a été mise à jour boolean addAll(Collection) // ajoute à la collection tous les éléments de la collection fournie en paramètre boolean addAll(Collection) // ajoute à la collection tous les éléments de la collection fournie en paramètre void clear() // supprime tous les éléments de la collection void clear() // supprime tous les éléments de la collection boolean contains(Object) // indique si la collection contient au moins un élément identique à celui fourni en paramètre boolean contains(Object) // indique si la collection contient au moins un élément identique à celui fourni en paramètre boolean containsAll(Collection) // indique si tous les éléments de la collection fournie en paramètre sont contenus dans la collection boolean containsAll(Collection) // indique si tous les éléments de la collection fournie en paramètre sont contenus dans la collection
50 Quelques méthodes de l’Interface Collection boolean isEmpty() // indique si la collection est vide boolean isEmpty() // indique si la collection est vide Iterator iterator() // renvoie un objet qui permet de parcourir l'ensemble des éléments de la collection Iterator iterator() // renvoie un objet qui permet de parcourir l'ensemble des éléments de la collection boolean remove(Object) boolean remove(Object) // supprime l'élément fourni en paramètre de la collection. La valeur de retour indique si la collection a été mise à jour boolean removeAll(Collection) boolean removeAll(Collection) supprime tous les éléments de la collection qui sont contenus dans la collection fournie en paramètre supprime tous les éléments de la collection qui sont contenus dans la collection fournie en paramètre int size() // renvoie le nombre d'éléments contenu dans la collection int size() // renvoie le nombre d'éléments contenu dans la collection Object[] toArray() // renvoie d'un tableau d'objets qui contient tous les éléments de la collection Object[] toArray() // renvoie d'un tableau d'objets qui contient tous les éléments de la collection
51 La Classe COLLECTIONS La classe Collections propose plusieurs méthodes de classe (static) La classe Collections propose plusieurs méthodes de classe (static) –qui effectuent des opérations sur des collections Ces traitements sont polymorphiques car ils demandent en paramètre un objet qui implémente une interface et retourne une collection Ces traitements sont polymorphiques car ils demandent en paramètre un objet qui implémente une interface et retourne une collection –Ex. void copy(List, List) // copie tous les éléments de la seconde liste dans la première –Enumaration enumeration(Collection) // renvoie un objet Enumeration pour parcourir la collection –Object max(Collection) // renvoie le plus grand élément de la collection selon l'ordre naturel des éléments –Object max(Collection, Comparator) // renvoie le plus grand élément de la collection selon l'ordre naturel précisé par l'objet Comparator
52 Classe Collections (suite) void sort(List) // trie la liste dans un ordre ascendant selon l'ordre des éléments défini par l'interface Comparable, qui est donc obligatoire pour les objets de la liste !! void sort(List) // trie la liste dans un ordre ascendant selon l'ordre des éléments défini par l'interface Comparable, qui est donc obligatoire pour les objets de la liste !! void sort(List, Comparator) // trie la liste dans un ordre ascendant selon l'ordre précisé par l'objet Comparator void sort(List, Comparator) // trie la liste dans un ordre ascendant selon l'ordre précisé par l'objet Comparator Si un élément dans la liste n’implémente pas l'interface Comparable : Si un élément dans la liste n’implémente pas l'interface Comparable : –une exception de type ClassCastException est levée
53 3 – La généricité (Cette partie sera étoffée avec les nouveautés de Java5 et les generics )
54 Rappel sur la généricité Problème du typage des données Problème du typage des données –chaque type a une représentation interne particulière –et un certain nombre d'opérateurs associés –conséquence: pour une même algorithme l'implémentation dépend du type La généricité vise donc à s'affranchir du type des données La généricité vise donc à s'affranchir du type des données –classes génériques –méthodes génériques
55 Java et la généricité Pas de mécanisme dédié pour la généricité Pas de mécanisme dédié pour la généricité –comme en C++ avec les templates Cependant en Java : Cependant en Java : –toutes les classes héritent implicitement de la classe Object –et en pratiquant le transtypage on peut transformer une instance de Object dans un type voulu Ainsi, en définissant un modèle au moyen de la classe Object Ainsi, en définissant un modèle au moyen de la classe Object –il est possible de structurer des données de type quelconque
56 Java et la généricité Mais l'absence pour l'instant de template en Java comporte des limites Mais l'absence pour l'instant de template en Java comporte des limites En effet un template est un modèle générique En effet un template est un modèle générique –il est expansé lors de son utilisation –la résolution de la définition appropriée des méthodes à utiliser est donc faite lors de l'utilisation du modèle
57 Java et la généricité En Java la classe qui traduit le modèle est compilée, d'où un certain nombre de problèmes En Java la classe qui traduit le modèle est compilée, d'où un certain nombre de problèmes –dans le cas du clonage la seule méthode clone connue à la compilation est celle de Object qui ne fait qu'une copie superficielle –dans le cas d'une comparaison, tout dépend dépend de la sémantique de l'objet qui est inconnue au moment de la traduction
58 Java et la généricité Toutefois dans bien des cas le mécanisme de généricité proposé est satisfaisant Toutefois dans bien des cas le mécanisme de généricité proposé est satisfaisant L'exemple suivant montre l'implémentation d'une pile L'exemple suivant montre l'implémentation d'une pile Il s'agit d'un cas d'école car la classe stack existe bien évidemment Il s'agit d'un cas d'école car la classe stack existe bien évidemment
59 Exemple de classe générique // classe générique qui implémente par un tableau // une pile d’objets de type quelconque class Pile { // constante de classe static final int Taille = 128; // attributs privés private int dimension; // taille du tableau private int sommet; // sommet de la pile private Object laPile[]; // le tableau qui gère la pile // méthode estVide qui indique l'état de la pile boolean estVide() { return sommet==-1 ? true : false; }
60 // définition des constructeurs // constructeur qui génère une exception personnelle définie par une classe plus loin Pile(int taille) throws PileException { if (taille < 0) if (taille < 0) throw new PileException("constructeur incorrect"); laPile = new Object[taille]; sommet = -1; dimension=taille;} // constructeur par défaut qui fait appel au constructeur précédent avec comme taille de pile la constante de classe appelée Taille Pile() throws PileException { this(Taille); } Pile() throws PileException { this(Taille); } Exemple de classe générique
61 Exemple de classe générique // méthode qui empile un élément dans la pile void empiler(Object elem) throws PileException { void empiler(Object elem) throws PileException {sommet++; if (sommet >= dimension) throw new PileException("pile pleine"); laPile[sommet] = elem; } // méthode qui retourne l'élément dépilé // méthode qui retourne l'élément dépilé Object depiler() throws PileException { Object depiler() throws PileException { if (sommet < 0) throw new PileException("pile vide"); return laPile[sommet--]; } } // fin de la classe Pile
62 Exemple de classe d'exception // définition d'une classe pour gérer les exceptions // de la classe Pile // de la classe Pile // cette classe hérite de la classe Exception // cette classe hérite de la classe Exception class PileException extends Exception class PileException extends Exception { // ne comprend que des constructeurs public PileException() {}; public PileException() {}; public PileException(String s) { super(s);}; } // fin classe PileException } // fin classe PileException
63 Exemple d'utilisation try { // pile d'objets de 5 instances de la classe Individu // pile d'objets de 5 instances de la classe Individu Pile pileIndividus = new Pile(5); Pile pileIndividus = new Pile(5); pileIndividus.empiler(new Individu("dupont","jean")); pileIndividus.empiler(new Individu("dupont","jean")); pileIndividus.empiler(new Individu("durand","pierre")); pileIndividus.empiler(new Individu("durand","pierre")); System.out.println("\n On depile "); System.out.println("\n On depile "); Individu ind; Individu ind; for (i=0; ! pileIndividus.estVide(); i++) { for (i=0; ! pileIndividus.estVide(); i++) { // transtypage obligatoire // transtypage obligatoire ind=(Individu)pileIndividus.depiler(); ind=(Individu)pileIndividus.depiler(); ind.affiche(); ind.affiche(); } } // fin du bloc try catch (PileException e) { // gestion de l'exception System.out.println("\n "+e.getMessage()+"\n\n"); }
64 Autres API que l’API standard, compilateur JIT et archive jar 4- Compléments de développement
65 Les autres API de Java Java Enterprise API : interaction entre Java et les systèmes client-serveur. Java Enterprise API : interaction entre Java et les systèmes client-serveur. Trois modules : Trois modules : –JDBC (Java DataBase Connectivity) : interaction entre Java et les bases de données (connexion à une base de données, envoi de requêtes SQL, réception des résultats). –Java IDL (Interface Definition Language) : objets mobiles, compatibles avec OMG IDL –Java RMI : invocation de méthodes à distance, pour les applications distribuées
66 Autres API (2) Java Commerce API : transactions commerciales sécurisées sur le Web (carte de crédit, monnaie électronique, etc.) Java Commerce API : transactions commerciales sécurisées sur le Web (carte de crédit, monnaie électronique, etc.) Java Server API : développement de serveurs intranet ou Internet en Java. Java Server API : développement de serveurs intranet ou Internet en Java.
67 Autres API (3) Java Media API : ensemble d’API pour la gestion du multimédia Java Media API : ensemble d’API pour la gestion du multimédia –Java 2D, Java Telephony, Java Animation, … Java Embedded API : destinée aux appareils électroniques Java Embedded API : destinée aux appareils électroniques – retour aux sources !.…
68 Compilateur JIT Just-In-Time Traduit les byte-codes en instructions natives Traduit les byte-codes en instructions natives Amélioration des performances Amélioration des performances Utile si les mêmes byte-codes sont exécutés plusieurs fois Utile si les mêmes byte-codes sont exécutés plusieurs fois Les JVMs supportent, pour la plupart, la compilation JIT Les JVMs supportent, pour la plupart, la compilation JIT
69 Fichier d’archive jar Les fichiers d’archives java permettent de déployer et de distribuer très facilement des bibliothèques de classes java Les fichiers d’archives java permettent de déployer et de distribuer très facilement des bibliothèques de classes java L’adjonction à l’archive d’un fichier de configuration particulier, appelé manifeste, permet de rendre l’archive exécutable L’adjonction à l’archive d’un fichier de configuration particulier, appelé manifeste, permet de rendre l’archive exécutable –Le manifeste contient les informations concernant la classe à exécuter au lancement de l’archive
70 Archive et packages Le nom d’une archive «.jar » n’a aucune signification particulière Le nom d’une archive «.jar » n’a aucune signification particulière Ce qui est beaucoup plus important est l’arborescence interne de l’archive qui doit respecter les conventions java concernant les packages Ce qui est beaucoup plus important est l’arborescence interne de l’archive qui doit respecter les conventions java concernant les packages –Si l’archive java ne comporte aucune arborescence interne c’est que les fichiers qu’elle comporte ne font partie d’aucun package.
71 Pour utiliser les bibliothèques contenues dans une archive java il suffit d’ajouter l’archive dans le « classpath » du compilateur « javac » et de la « machine virtuelle java » Pour utiliser les bibliothèques contenues dans une archive java il suffit d’ajouter l’archive dans le « classpath » du compilateur « javac » et de la « machine virtuelle java » Le développeur devra ensuite spécifier au besoin les packages à importer au début de ses fichiers sources java Le développeur devra ensuite spécifier au besoin les packages à importer au début de ses fichiers sources java
72 Exécution d’une archive Pour exécuter une archive java, il faut utiliser la commande suivante Pour exécuter une archive java, il faut utiliser la commande suivante java [options] –jar archive_java.jar [classe_principale] Pour les versions 1.1 et antérieures de la machine virtuelle, il faut utiliser la commande « jre archive_java archive_java.jar classe_principale » Pour les versions 1.1 et antérieures de la machine virtuelle, il faut utiliser la commande « jre archive_java archive_java.jar classe_principale » Pour les version 1.2 et supérieures de la machine virtuelle, si l’archive java intègre un manifeste précisant la classe principale à exécuter, il n’est pas besoin de préciser celle-ci Pour les version 1.2 et supérieures de la machine virtuelle, si l’archive java intègre un manifeste précisant la classe principale à exécuter, il n’est pas besoin de préciser celle-ci
73 Construction d’une archive Pour créer une archive java, il suffit d’exécuter la commande Pour créer une archive java, il suffit d’exécuter la commande jar -cf nom_archive liste_des_fichiers –où les différents fichiers de la liste sont séparés par des espaces –L’option « c » spécifie que l’on souhaite créer une archive –L’option « f » permet d’envoyer le flux dans l’archive dont le nom est spécifié –L’option « v », pour verbose, permet de suivre l’évolution de la création de l’archive
74 Extraction d’une archive Pour extraire le contenu d’une archive java, il suffit d’exécuter la commande : Pour extraire le contenu d’une archive java, il suffit d’exécuter la commande : jar -xf nom_archive [liste_des_fichiers_à_extraire] Bien qu’il n’ait pas été conçu pour cela, le format «.jar » peut être à l’occasion utilisé pour compresser des fichiers Bien qu’il n’ait pas été conçu pour cela, le format «.jar » peut être à l’occasion utilisé pour compresser des fichiers –au même titre que le format zip ou rar En effet, la commande jar, fournit avec toutes les distributions du SDK, peut être utilisé sur des plateformes variées. En effet, la commande jar, fournit avec toutes les distributions du SDK, peut être utilisé sur des plateformes variées.
75 Ajout d’un fichier texte « manifeste » Le manifeste est un fichier texte qui permet, entre autres, de spécifier la classe qui sera exécutée lors du lancement d’une archive. Le manifeste est un fichier texte qui permet, entre autres, de spécifier la classe qui sera exécutée lors du lancement d’une archive. Pour définir le manifeste, il suffit d’écrire un fichier texte et de le passer en paramètre lors de la création de l’archive en utilisant l’option « m » Pour définir le manifeste, il suffit d’écrire un fichier texte et de le passer en paramètre lors de la création de l’archive en utilisant l’option « m » jar -cvmf nom_manifeste nom_archive liste_des_fichiers
76 Fichier manifeste (2) L’ordre de passage des arguments «nom_manifeste » et « nom_archive » doit être le même que l’ordre des options « m » et « f » L’ordre de passage des arguments «nom_manifeste » et « nom_archive » doit être le même que l’ordre des options « m » et « f » Le fichier texte « nom_manifeste » doit être écrit avec son extension (qui peut être quelconque puisqu’en réalité, c’est le contenu du fichier qui sera recopié dans le manifeste de l’archive). Le fichier texte « nom_manifeste » doit être écrit avec son extension (qui peut être quelconque puisqu’en réalité, c’est le contenu du fichier qui sera recopié dans le manifeste de l’archive). Le manifeste est créé sous le nom « MANIFEST.MF » dans un répertoire « META-INF » se situant à la racine de l’archive. Le manifeste est créé sous le nom « MANIFEST.MF » dans un répertoire « META-INF » se situant à la racine de l’archive.
77 Ecrire un manifeste (3) Le manifeste comporte un renseignement par ligne Le manifeste comporte un renseignement par ligne Chaque ligne est du type : Chaque ligne est du type : renseignement : valeur Chaque ligne, pour être valide, doit obligatoirement se terminer par un caractère de retour à la ligne Chaque ligne, pour être valide, doit obligatoirement se terminer par un caractère de retour à la ligne –attention donc à ajouter ce caractère à la fin de la dernière ligne du fichier
78 Informations potentielles d’un fichier manifeste Manifest-Version: 1.0 (le manifeste est conforme aux spécifications 1.0 sur la rédaction des manifestes) Manifest-Version: 1.0 (le manifeste est conforme aux spécifications 1.0 sur la rédaction des manifestes) Main-Class: classname (à partir de la version 1.2 du manifeste, spécifie le nom de la classe à exécuter lors du lancement de l’archive). Main-Class: classname (à partir de la version 1.2 du manifeste, spécifie le nom de la classe à exécuter lors du lancement de l’archive). Implementation-Title : "titre du package" Implementation-Title : "titre du package" Implementation-Version : "n° de version " Implementation-Version : "n° de version " Implementation-Vendor : "organisation vendant le produit" Implementation-Vendor : "organisation vendant le produit" Specification-Title : "titre de la spécification" Specification-Title : "titre de la spécification" Specification-Version : "n° de version " Specification-Version : "n° de version " Specification-Vendor : "organisation vendant le produit" Specification-Vendor : "organisation vendant le produit"