Généricité & Collections en JAVA

Computer Science, Programming in Java · notes

Voir tous les documents en programmation

TP

Généricité & collections en JAVA

Objectifs

S’initier au concept de généricité.

- - Apprendre à manipuler

les collections

Temps alloué Outils

4h30

Eclipse

génériques

La généricité

Exercice 1 : Pile générique en représentation chaînée

Vous disposez du code suivant représentant l’implémentation d’une pile

// interface Pile interface Pile {

public boolean estVide(); public Object dernier(); public void depiler(); public void empiler(Object o);

} /* Le recours à une interface peut s’expliquer par la possibilité après de faire le choix de la représentation physique voulue (chainée ou contigüe) */ // Représentation chainée : listes de Object class Noeud {

Object info; Noeud suivant;

} // implémenter les Pile avec des listes (représentation chainée) class PileListe implements Pile{ private Noeud sommet; public PileListe(){

sommet = null;

} public boolean estVide(){

return (sommet == null);

} public Object dernier(){

return sommet.info;

} public void empiler(Object o){

Noeud n = new Noeud(); n.info = o; n.suivant = sommet; sommet = n;

} public void depiler(){

sommet = sommet.suivant;

CHALOUAH.Anissa

1

}

} class TestPile{

public static void main(String[]args){

PileListe p = new PileListe(); for(int i = 0 ; i < 10 ; i++)

p.empiler(new Integer(i));

while(!p.estVide()){ System.out.println((Integer) p.dernier()); p.depiler();

} // Tester aussi p.empiler("L'entier " + i); /* System.out.println((Integer) p.dernier());

=> Erreur à l'exécution de casting => System.out.println(p.dernier()); => Ouverture sur les exceptions */ /* Remplacer while(!p.estVide()) par for(int i = 0 ; i < 20 ; i++) => Erreur à l'exécution lors du dépilement d'une pile vide => Ouverture sur les exceptions mais surtout sur la généricité */

}

}

Donnez la version générique de l’implémentation de la pile

Les collections génériques

CHALOUAH.Anissa

2

Les types génériques servent particulièrement dans les collections de données. Dans

l’API Java, la plupart de ces structures de données de bases sont déjà implémentées

dans le package java.util, qui fournit une petite hiérarchie.

Notez que toutes ces interfaces sont définies de manière générique : il faut donc

spécifier le type qu’elles utilisent lorsqu’on les implémente et qu’on les manipule.

Publicité

- L’interface de base est Collection qui désigne n’importe quel regroupement

d’objets.

o Un Set est une collection qui n’autorise pas la duplication d’un

élément.

o Une List est un ensemble d’éléments ordonnés, c’est à dire une

séquence d’éléments.

o Une Queue est une collection qui conserve un ordre de manipulation,

selon une logique FIFO. Elle est particulièrement utile pour traiter des

suites d’´évènements.

- Une Map n’est pas une collection : c’est un objet qui associe des clefs `à des

valeurs. Une table de hachage par exemple, sera vue comme une Map. D’autre

part les Set et les Map peuvent être Sorted, c’est `à dire que leurs ´éléments

seront constamment ordonnés et que cet ordre sera conservé même après

des opérations d’ajout ou de retrait d’´éléments.

CHALOUAH.Anissa

3

Quelques implémentations de ces interfaces sont fournies, et dont le nom indique la

méthode utilisée pour leur implémentation: ArrayList, LinkedList, HashSet,

HashMap, ...

D’autre part la classe Collections (avec un ‘s’) regroupe un grand nombre de

fonctions statiques utiles aux manipulations de ces structures de données.

Enfin, il faut noter que l’interface Collection étend l’interface Iterable. Cette dernière

demande juste qu’un objet puisse obtenir un Iterator avec la méthode iterator(). Un

Iterator doit implémenter les méthodes hasNext() et next() (optionnellement

remove()). Le gros avantage d’un objet Iterable est qu’on peut le manipuler avec la

construction foreach :

List<Integer> l = new LinkedList<Integer>();

/* do something with l */

for (Integer i : l) {

/* do something with i */

}

Exercice 2 : Pile et collection générique (ArrayList)

Vous disposez maintenant du code suivant représentant l’implémentation contigu d’une pile.

public class PileTab {

int pos; int [] tab;

public PileTab(){

tab = new int[4]; this.pos = 0;

}

public void add(int e){

if (this.pos == tab.length){

System.out.println("Ajout impossible de "+e); //System.exit(-1);

} else {

CHALOUAH.Anissa

4

tab[this.pos] = e; this.pos ++;

}

}

public int remove(){

Publicité

int elem = tab[this.pos-1]; this.pos --; return elem;

}

public boolean estVide(){

return this.pos == 0;

}

public int size(){

return this.pos;

}

public void affiche(){

for (int i = 0; i<this.pos; i++){

System.out.println(this.tab[i]);

}

}

public int getSommet(){

return this.tab[pos-1];

}

}

Question :

1) Testez cette classe dans votre programme principal 2) Transformer ce code en un type paramétré PileGen de façon à ce qu’on puisse ajouter n’importe quel type d’objet dans la pile. Le champ tableau devient un champ ArrayList <T> dont la taille est extensible, donc vous n’avez plus besoin du champ pos, vous pouvez utiliser directement la méthode size() de l’ArrayList. Dans la méthode d’affichage, vous utiliserez la méthode classique de parcours.

3) Testez La classe PileGen dans votre programme principal en

Exercice 3 : Pile et collection générique (LinkedList)

Voici une interface définissant un type abstrait "Pile de <A>" avec les fonctionnalités classiques d'une pile :

public interface IPile <A> {

boolean estVide(); void empile(A a); A depile(); // retourne l'élément en sommet de pile et dépile int nbElements();

CHALOUAH.Anissa

5

A sommet(); // retourne le sommet de pile mais ne le dépile pas

}

1) Écrivez une classe générique CPile qui implémente l'interface IPile. Vous stockerez les éléments de la pile dans une liste chaînée (instance de java.util.LinkedList, voir en annexe quelques méthodes publiques de cette classe).

2) Écrivez un petit programme qui crée et manipule des piles en instanciant la classe générique de différentes façons (par exemple pile de String, pile de Integer, …).

Exercice 4 : Compréhension de l’architecture des tâches

L’architecture des tâches est donnée à la figure 1 où le détail des classes

TacheElementaire et TacheComplexe n’est pas donné.

Une tâche est caractérisée par un nom et un coût. Une tâche est soit une tâche

élémentaire, soit une tâche complexe qui est alors composée de sous-tâches.

Il est ainsi possible d’ajouter une sous-tâche à une tâche complexe, ajouter(Tache)

ou de supprimer une sous-tâche, supprimer(Tache). Le coût d’une tâche complexe

est la somme des coûts des tâches qui la composent.

1) Écrire en Java la classe TacheElementaire qui est une réalisation de

l’interface Tache.

CHALOUAH.Anissa

6

public interface Tache {

/** Obtenir le nom de la tâche. */ String getNom();

/** Obtenir le coût de la tâche. */ int getCout();

}

Définition d’une tâche complexe

Nous nous intéressons maintenant à la classe TacheComplexe, en particulier à sa

Publicité

relation avec l’interface Tache. Une tâche complexe est composée d’un nombre

quelconque de tâches. On décide d’utiliser l’interface java.util.Collection pour

stocker les sous-tâches. On l’utilisera bien entendu dans sa version générique.

Comme on souhaite pouvoir parcourir toutes les sous-tâches d’une tâche complexe,

la classe TacheComplexe réalise l’interface java.lang.Iterable.

2) Indiquer quel est le principal intérêt de la généricité. 3) Écrire en Java la classe TacheComplexe. 4) Écrire un programme qui crée des tâches et des tâches complexes et qui

affiche leur coût total.

Exercice 5 : Collection générique HashMap

L’objectif de cet exercice est de réaliser un annuaire pour mémoriser des numéros

de téléphone et des adresses. Chaque entrée est représentée par une fiche à

plusieurs champs : un nom, un numéro et une adresse.

Travail à faire :

1) Écrire la classe Fiche. Celle-ci devra avoir un constructeur à 3 paramètres

pour initialiser l’ensemble des attributs de la classe et 1 constructeur à 1

paramètre auquel on passera le nom (Les autres champs sont initialises par

défaut a -1 (numéro) et null (adresse)).

La classe Annuaire comporte une table associative (HashMap<String , Fiche>)

qui sera faite d’associations (un nom , une Fiche).

CHALOUAH.Anissa

7

2) Écrire la classe Annuaire dont le constructeur permettra la création d’une

table associative de type HashMap. Celle-ci doit comporter les méthodes

suivantes :

a. public void getNBconttacts() qui retourne le nombre de contacts

dans l’annuaire

b. public void addContact(Fiche f)qui ajoute un contact à partir

d’une fiche passé en paramètre.

c. public void addContact(String s, int n, String a) qui ajoute

un contat a partir d’un nom, d’un numéro et d’une adresse passés en

paramètre.

d. public void addContact(String s) qui ajoute un contact à partir

du nom passé en parameter (numéro et adresse par défaut)

e. public int getnumero(String name)qui retourne le numéro de

telephone associé au nom passé en paramètre

f. public void affiche()qui affiche les contacts dans l’annuaire.

3) Réalisez une classe Test afin d’y tester toutes vos méthodes

CHALOUAH.Anissa

8

Annexe

la classe LinkedList java.util Class LinkedList<E> java.lang.Object java.util.AbstractCollection<E> java.util.AbstractList<E> java.util.AbstractSequentialList<E> java.util.LinkedList<E>

Type Parameters : E - the type of elements held in this collection Quelques méthodes publiques :

 LinkedList() Constructs an empty list.  void addFirst(E o) Inserts the given element at the beginning of this list.  E element() Retrieves, but does not remove, the head (first element) of this

list. Throws : NoSuchElementException - if this queue is empty.

 E getFirst() Returns the first element in this list.

Throws: NoSuchElementException - if this list is empty.

CHALOUAH.Anissa

9