Programmation
Orientée
Objet
TP n°
4
Listes
chaînées,
généricité, vecteur, énumération
a) Écrire le code java
correspondant aux classes Noeud,
Liste
et TestListe
.
La classe Noeud aura
pour attributs
nom de type String et
suivant de type Noeud qui est un pointeur vers un autre nœud (qui sera l'élément suivant de la liste)
et pour méthodes
les constructeurs ayant comme argument soit le nom seul, soit l'ensemble des attributs d'une instance
getNom et getSuivant pour lire les attributs nom et suivant
setNom et setSuivant avec comme argument respectif la nouvelle valeur pour l'attribut nom et suivant.
toString()
La classe Liste aura
pour attributs :
debut de type Noeud qui pointe sur le premier élément de la liste
et les méthodes
constructeur sans argument ou un nom (de type String)
insererDebut qui aura pour argument un nom de type String ; un nouveau nœud avec ce nom sera instancié et placé en début de liste
toString ou lireListe()
La
classe TestListe
comportera la méthode main
où seront crées de nouvelles listes, avec appel à
leurs méthodes.
b) Compléter la classe Liste afin d'avoir 2 méthodes supplémentaires :
taille qui renvoie la longueur (le nombre d'éléments de la liste). Pour une liste vide, le résultat est 0. La longueur de la liste peut être soit un attribut incrémenté lors de chaque insertion, soit calculée.
insererPositionDonnee(String nom, int position) qui insère un nouveau nœud avec le nom donné en argument en position donnée. La numérotation de la position débute à 0. Ainsi, le premier élément de la liste sera en position 0.
c) Comme la classe Noeud est uniquement utilisée dans la classe Liste, donner une meilleure encapsulation de votre code.
2. Listes doublement chaînées
Modifier le code afin que les listes soient à présent doublement chaînées.
dans la classe Noeud, ajouter un attribut precedent de type Noeud,
dans la classe Liste, ajouter un attribut dernier de type Noeud qui pointe sur le dernier élément de la liste. Ajouter des méthodes pour lire la liste à partir de la fin, ajouter directement un élément en fin de liste. Modifier le code de insererPositionDonnee.
Exercice 2. Généricité
La généricité permet de paramétrer une classe ou une méthode par un type qui ne sera défini que lors de l'utilisation de l'objet. On utilise la notation <T> pour indiquer que l'objet prend un type générique.
Soit l'exemple :
class Paire<T> { T x, y ; Paire(T x1, T y1) { x = x1 ; y = y1 ; } T first() { return x ; } T second() { return y ; } void setFirst(T x1) { x = x1 ; } void setSecond(T y1) { y = y1 ; } void invert() { T temp = x ; x = y ; y = temp ; } boolean equals(Paire<T> o) { return o.x.equals(x) && o.y.equals(y) ; } public String toString() { return "" + x + " " + y ; } } // class Paire<T> class TestPaire { public static void main(String[] args) { Paire<String> paire1 = new Paire<String> ("premier", "second"); System.out.println(paire1); } } |
En vous inspirant de cet exemple,
reprendre l'exercice sur les listes chainées pour avoir des listes de types génériques
écrire un programme test utilisant la classe générique qui vient d'être construite : liste de String, liste d'Integer, ...
Exercice 3. Vecteurs, énumération
Dans java.util, vous trouverez la classe Vector<E> ainsi que l'interface Enumeration<E>.
Noter que la classe et l'énumération sont génériques. Dans les premières versions de java, leurs composants étaient de type Object ce qui demandait des cast et des vérifications de type.
La classe Vector implémente un tableau d'objets qui peut grandir. Tout comme un tableau, il contient des composants qui peuvent être accédés par un index entier. Toutefois, la taille d'un vecteur peut s'accroître ou diminuer en fonction des besoins selon que l'on ajoute ou supprime des articles après la création du vecteur.
Pour une instance de vecteur, on dispose de
sa taille (méthode : int size()) qui donne le nombre effectif de composants du vecteur.
sa capacité (méthode : int capacity()) : capacité de stockage du vecteur. Elle est toujours au moins aussi grande que la taille du vecteur.
CapacityIncrement : valeur d'incrément pour la capacité. Quand des composants sont ajoutés au vecteur, la capacité augmente de la valeur de capacityIncrement.
La méthode void ensureCapacity(int) peut être utilisée dans une application pour augmenter la capacité du vecteur avant d'insérer un grand nombre de composants ; cela réduit le nombre de re-allocations.
La classe Vector dispose de plusieurs constructeurs. Dans tous les cas, le vecteur est vide (taille =0). La capacité vaut 10 par défaut. Dans la documentation en ligne l'incrément vaut 0 par défaut ; dans les tests il semblerait plutôt que si non spécifiée, capacityIncrement a même valeur que capacity.
Consulter la documentation en ligne pour voir le détail des méthodes de la classe.
La méthode elements() a pour type de retour Enumeration<E>.
Un objet qui implémente l'interface Enumeration génère une série d'éléments, un à la fois. La méthode hasMoreElements teste si l'énumération comporte d'autres éléments ; la méthode nextElement renvoie le prochain élément de l'énumération si cette instance d'énumération a au moins encore un élément à fournir. Des appels successifs à la méthode nextElement renvoie les éléments successifs de la série.
Ainsi, par exemple, pour afficher tous les éléments d'un Vector<E> v :
for (Enumeration<E> e = v.elements(); e.hasMoreElements();) System.out.println(e.nextElement()) ; |
Application : écriture comptable
En vue d'informatiser la comptabilité d'une entreprise, définissez les classes Ecriture, Compte et EcritureComptable.
La classe Ecriture est destinée à représenter une écriture comptable, c'est-à-dire une ligne dans un livre de comptes. Une écriture est faite d'un certain nombre de variables d'instances, comme
date (type Date pour ne pas se compliquer la vie) exprimant la date de l'opération dont cette écriture est la trace,
libellé (type String) décrivant la nature de cette opération,
crédit (type boolean) qui vaut true si c'est une opération de crédit (une « recette ») et false si c'est un débit (« une dépense »)
montant (type double) la somme en question.
Pour ne pas trop alourdir l'exercice contentez-vous de définir
un constructeur public qui permet d'initialiser toutes ces variables d'instance et
la méthode public String toString() qui transforme l'écriture en une chaine de caractères.
Pour la saisie et l'affichage des dates, vous pouvez vous inspirer de l'exemple suivant :
import java.util.*; // Date import java.text.*; // SimpledateFormat, ParsePosition, ...
public static void main(String [] args) { // mise en forme de dates SimpleDateFormat format1 = new SimpleDateFormat("dd MMMM yyyy"); SimpleDateFormat format2 = new SimpleDateFormat("dd MM yyyy"); Date d; d = new Date(); // initialisation date du jour System.out.println("date : "); System.out.println("par defaut : "+d); // → Tue Sep 21 12:20:57 CEST 2010 System.out.println("dd MMMM yyyy : " +format1.format(d)); // → 21 septembre 2010
// initialisation au 21 septembre 2010 d = format2.parse("21 09 2010", new ParsePosition(0)); System.out.println("date : " +format1.format(d)); System.out.println(); } // main
} //class |
Un compte a 3 attributs :
un intitulé de type String ;
écritures : l'ensemble des écritures de type Vector<Ecriture> ; les écritures se trouvent dans l'ordre où on les a enregistrées
un solde (de type double) découlant de toutes ces écritures.
La classe compte aura pour méthodes publiques :
un constructeur ayant pour argument l'intitulé du compte ;
void ajout (Date date, String libelle, boolean credit, double montant) : ajout d'une écriture comptable ;
double solde() : obtention de la valeur du solde du compte ;
String toString() : conversion du compte en une chaîne de caractères en vue de son affichage
La classe EcritureComptable comporte la méthode main pour faire les tests.