La structure des programmes objets et leur modularité permet de créer une documentation structurée facilement utilisable.
La documentation permet la réutilisation des programmes et leur extension. Un programme n'est jamais trop documenté.
En Java, l'outil javadoc (fourni avec le JDK) permet de générer une documentation HTML à partir de commentaires contenus dans le code.
Il est également possible de fournir à l'outil javadoc des fichiers de documentation des paquetages, des images, etc.
Documentation (1/3)
Documentation (2/3)
Chaque entité (classe, attribut, méthode, etc) peut être commentée. Un commentaire s'écrit entre /** et */.
Les commentaires peuvent contenir des tags prédéfinis.
/** Cette classe mod\u00e8lise les primates bip\u00e9des * <img src="vitruve.jpg">.
* @author tartempion * @version 21
* @see <a href="Primate.html">Primate</a> */
public class Humain{
private int taille;
private boolean male;
/** Le nombre de chromosomes. */
public static final int nbChromosomes = 24;
...
/** @return Cette m\u00e8thode renvoie le poids id\u00e8al de * l'humain selon sa taille et son sexe.
* @throws TropGrosException */
public float poidsIdeal(){
...
} ...
}
Le programme javadoc peut ne prendre en compte que les membres publics, ou d'autres, selon les options.
javadoc Humain.java ►
Documentation (3/3)
En plus des tableaux, Java offre dans le package java.util des classes implémentant des structures de données : listes, ensembles, tableaux associatifs, tables de hachage, et même des arbres.
Structures de données en Java
Collection
List Set Queue Deque
Map
AbstractSequentialList ArrayList Vector
AbstractList
LinkedList
AbstractMap
HashMap
HashTable
TreeMap
Stack
HashSet EnumSet
Collection est une interface générique qui offre des méthodes d'ajout, de suppression, de recherche, etc.
Iterator est une interface offrant des méthodes pour le parcours séquentiel d'une structure linéaire.
Collection
boolean add(T o) void clear()
boolean contains(Object o) boolean remove(Object o) int size()
T[] toArray(T[] t)
Iterator<T> iterator() ...
boolean hasNext() T next()
void remove()
L'interface Iterator permet de supprimer des éléments en cours de parcours (méthode remove).
Syntaxe de type foreach (ne permet pas la modification en cours de parcours) :
ListIterator, sous interface de Iterator, permet de parcourir une liste dans les deux sens (seulement pour les List).
Iterator
ArrayList<Integer> l = new ArrayList<Integer>();
for(int i=0;i<100;i++) l.add((int) (Math.random()*100));
for(Iterator i = l.iterator();i.hasNext();){
System.out.println(i.next());
}
ArrayList<Integer> l = new ArrayList<Integer>();
for(int i=0;i<100;i++) l.add((int) (Math.random()*100));
for(Integer i : l){
System.out.println(i.next());
}
List est une interface qui ajoute à Collection des méthodes de consultation :
List est implémentée par ArrayList, Vector, LinkedList, etc.
ArrayList est une implémentation de liste par tableau, efficace pour l'accès aux éléments, mais non synchronisée.
Vector est une implémentation de liste par tableau et synchronisée, donc un peu moins efficace qu'ArrayList, mais sans problème d'accès concurrent de threads différents.
LinkedList est une implémentation de liste doublement chainée, non synchronisée, efficace pour l'ajout ou la suppression d'élément.
List (1/2)
T get(int i)
int indexOf(Object o) ...
Les accés à une liste doivent être synchronisés sous peine de comportement incohérent.
Pour avoir une liste synchronisée, utiliser une classe de listes synchronisées ou la méthode de synchronisation de la classe Collections :
List (2/2)
l.remove(4);
2 3 7 9 1
processus p1
l.remove(4);
processus p2
LinkedList<String> l = new LinkedList<String>();
for(int i=0;i<12;i++) l.add("A"+i);
List<String> synchroL = Collections.synchronizedList(l);
synchroL.add("bidule");
Set est une interface pour les ensembles d'éléments forcément différents (au sens de equals pour les objets). Set est implémentée par EnumSet et HashSet.
EnumSet est une implémentation d'ensemble pour les types énumérés :
HashSet est une implémentation d'ensemble par table de hachage.
Les Set peuvent aussi être synchronisés.
Set
enum ArcEnCiel{rouge, orange, jaune ,vert, bleu, indigo, magenta, violet};
public static void main(String[] arg){
EnumSet<ArcEnCiel> s = EnumSet.range(ArcEnCiel.vert,ArcEnCiel.magenta);
for(Iterator i = s.iterator();i.hasNext();) System.out.println(i.next());
}
Map est interface de tableau associatif (couples clé-valeur).
HashMap est une implémentation de Map par table de hachage, non synchronisée, avec possibilité de clé et valeur null.
Hashtable est une implémentation de Map par table de hachage, synchronisée, et n'autorise pas les valeurs null.
Map
V put(K a, V b) V get(Object o) V remove(Object o) Set<K> keySet()
Collection<V> values() int size()
...
HashMap<String,Integer> hm = new HashMap<String,Integer>();
hm.put("Toto",20);
int i = hm.get("Toto");
Collections est une classe offrant des méthodes static de manipulation de Collection : synchronisation, tri, recherche, inversion, permutation, etc
Il existe aussi une classe Arrays qui offre les mêmes méthodes pour les tableaux.
Collections
LinkedList<int[]> l = new LinkedList<int[]>();
int[] t = {0,0,0};
l.add(t);l.add(t);
t = new int[4];
for(int i=0;i<t.length;i++) t[i] = 2;
Collections.fill(l,t);
for(int[] tab : l)
for(int i=0;i<tab.length;i++) System.out.println(tab[i]);
Collections.reverse(l);
System.out.println(Collections.frequency(l,t));
Les méthodes de Collections , en particulier de tri, utilise des méthodes de comparaisons.
Exemple : on veut trier une liste de personnes par nom ou par âge.
Il faut que les objets de la liste implémentent des méthodes de comparaison. Par défaut, Collections.sort(List l) utilise l'interface Comparable .
Comparable et Comparator (1/3)
class Personne{
String nom, prenom;
int age;
static LinkedList<Personne> gens = new LinkedList<Personne>();
...
Collections.sort(gens);
...
}
On peut spécifier la méthode de comparaison à utiliser en implémentant l'interface Comparator.
Comparable et Comparator (2/3)
class Personne implements Comparable<Personne>{
String nom, prenom;
int age;
static LinkedList<Personne> gens = new LinkedList<Personne>();
...
public int compareTo(Personne o){
return this.nom.compareTo(o.nom);
} ...
Collections.sort(gens);
...
}
class ComparePersonneParAge implements Comparator<Personne>{
public int compare(Personne p1, Personne p2){
return p1.age - p2.age;
}
Comparator est un exemple de l'utilisation du patron de conception Strategy, dont le but est de permettre de modifier le comportement des objets au cours de l'exécution du programme.
Comparable et Comparator (3/3)
class Personne implements Comparable<Personne>{
String nom, prenom;
int age;
static LinkedList<Personne> gens = new LinkedList<Personne>();
...
public int compareTo(Personne o){
return this.nom.compareTo(o.nom);
} ...
Collections.sort(gens);
...
Collections.sort(gens,new ComparePersonneParAge());
...
}
Sérialiser un objet consiste à le sauvegarder dans un fichier ou un flux.
- échange d’objets entre applications distantes
- sauvegarde de l’état d’exécution d’un programme
Il faut sauvegarder les valeurs d’attributs et la façon de recréer l’objet (classe avec constructeur)
Tout objet implémentant l’interface
java.io.Serializable
est sérialisable.Serializable
n’a aucune méthode (interface de marquage).Les interfaces
ObjectOutput
etObjectInput
offrent des méthodes de sérialisation et de désérialisation :void writeObject(Object o) Object readObject()
Sérialisation (1/2)
Comportement par défaut de la sérialisation : toutes les valeurs des attributs non static ou transient sont sauvées. Des informations sur la classe (types et noms des attributs) sont aussi sauvées pour permettre de recréer l'objet.
Sérialisation (2/2)
class C implements Serializable ...
...
C c = new C();
File f = new File("Toto.truc");
ObjectOutput os = new ObjectOutputStream(new FileOutputStream(f));
os.writeObject(c);
os.close();
...
...
ObjectInput is = new ObjectInputStream(new FileInputStream(f));
C c = (C) is.readObject();
is.close();
...
Clonage (1/2)
Cloner un objet consiste à le répliquer, avec les mêmes valeurs d’attribut.
- préserver l’état d’un objet avant un traitement
- gagner du temps si la création par constructeur est très lourde
Tout objet implémentant l’interface
java.lang.Cloneable
est clonable.Cloneable
n’a aucune méthode (interface de marquage).cloner = appeler la méthode
Object clone()
de la classeObject
Clonage de surface : on ne clone pas les valeurs des attributs - comportement par défaut de la méthode
clone()
Clonage profond : on clone récursivement les valeurs, jusqu’à aboutir à des valeurs de types primitifs
Clonage (2/2)
public class Personne implements Cloneable{
private String nom;
private ArrayList<Personne> amis;
Personne(String n){
this.nom = n;
this.amis = newArrayList<Personne>();
}
public void addAmi(Personne p){ this.amis.add(p); } public Object clone(){
Personne p = new Personne(this.nom);
for(Personne e:this.amis) p.addAmi(e);
return p;
}
public Object deepCopy(){
Personne p = new Personne(this.nom);
for(Personne e:this.amis) p.addAmi((Personne) e.deepCopy());
return p;
} }
une sérialisation suivie d’une désérialisation = un clonage profond