Genericity & Collections in Java

Page 1 sur 9Lecteur de document UniversityLib

Genericity & Collections in Java

Computer Science - Java Programming · notes

Voir tous les documents en programmation

| | | | | | | | --- | --- | --- | --- | --- | --- | | ![](data:image/png;base64...) | **TP** **Généricité & collections en JAVA** | | | | ![](data:image/png;base64...) | | | | | | | | | **Objectifs** | | | **Temps alloué** | | **Outils** | | * S’initier au concept de généricité. * Apprendre à manipuler les collections génériques | | | 4h30 | | Eclipse |

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;

Publicité

}

}

**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

![](data:image/png;base64...)

![](data:image/png;base64...)

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.

* L’interface de base est **Collection** qui désigne n’importe quel regroupement d’objets. + Un **Set** est une collection qui n’autorise pas la duplication d’un élément. + Une **List** est un ensemble d’éléments ordonnés, c’est à dire une séquence d’éléments. + 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.

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.

Publicité

**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** {

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

**this**.pos ++;

}

}

**public** **int** remove(){

**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 :**

Publicité

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();

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.

![](data:image/png;base64...)

1. Écrire en Java la classe TacheElementaire qui est une réalisation de l’interface Tache.

**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 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.

1. Indiquer quel est le principal intérêt de la généricité. 2. Écrire en Java la classe TacheComplexe. 3. É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).

1. É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 : 1. **public** **void** getNBconttacts() qui retourne le nombre de contacts dans l’annuaire 2. **public** **void** addContact(Fiche f)qui ajoute un contact à partir d’une fiche passé en paramètre. 3. **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. 4. **public** **void** addContact(String s) qui ajoute un contact à partir du nom passé en parameter (numéro et adresse par défaut) 5. **public** **int** getnumero(String name)qui retourne le numéro de telephone associé au nom passé en paramètre 6. **public** **void** affiche()qui affiche les contacts dans l’annuaire. 2. Réalisez une classe Test afin d’y tester toutes vos méthodes

**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.