Master 2 BBSG POO, langage Java Henri Garreta et Laurent Tichit 6. Types paramé
Master 2 BBSG POO, langage Java Henri Garreta et Laurent Tichit 6. Types paramétrés 1. Création d’une collection par sélection d’éléments 2. Transformation des éléments d'une collection 3. Réduction des éléments d'une collection AVERTISSEMENT. Les classes et interfaces liées aux collections, subissent à partir de la version 5 de Java une importante modification, puisqu’elles deviennent « génériques ». Cela se manifeste, notamment dans la documentation en ligne, par une notation spéciale : le signe <E> (comme « Element ») à côté du nom, qui représente un type (une interface, ou plus rarement une classe) : public interface Collection<E> { ... } A cause de la généricité, si vous utilisez des collections d'Object et non pas des collections génériques avec Java5 (et supérieur), vous risquez d’obtenir des avertissements concernant des opérations « incontrôlées » ou « dangereuses » : Note: MachinTruc.java uses unchecked or unsafe operations. Pour éviter ces messages, soit vous utilisez les collections génériques, soit (vous vous contentez de rester dans la préhistoire) il vous suffit de compiler votre fichier source en indiquant qu’il relève de Java 1.4 : javac -source 1.4 <fichiers_à_compiler> (la version 1.4 précède immédiatement la version 5). Utilisateurs d’Eclipse, pour obtenir le même résultat vous devez aller dans Project > Properties > Java Compiler, cocher la case Enable project specific settings et jouer sur l’indication du champ Compiler compliance level. POURQUOI ? Pour des raisons de sécurité, la machine virtuelle Java 1.4 (et les précédentes) teste les types des éléments insérés dans les collections (et extraits de celles-ci). Ces tests ont lieu à l'exécution (on parle alors de tests dynamiques) si on utilise Java 1.4 (ou inférieur) car à la compilation, il est impossible de connaître le type des données – elles sont vues simplement comme des Object. Si on utilise les version génériques (Java 5+), ces tests peuvent (enfin!) avoir lieu à la compilation (tests statiques) car on déclare le type des éléments => meilleures performances ! Si on utilise les collections non-génériques avec Java5+, il faut donc le déclarer ! 6.1. Création d’une collection par sélection d’éléments A - En supposant qu’une interface CritereSelection a été ainsi définie public interface CritereSelection { boolean ok(Object x); } écrivez une classe TestSelection avec une méthode de signature static Collection<Integer> selection(Collection<Integer> source, CritereSelection critere); qui renvoie la collection formée des éléments de source qui satisfont le critere donné. Écrivez une fonction main qui • crée une liste – un ArrayList, ou une LinkedList, etc. – portant les nombres entiers de 0 à 100 (des objets Integer), • appelle la méthode selection pour en extraire la liste des multiples de 3, • affiche le résultat obtenu. Faites en sorte que selection renvoie un objet de type Collection<Integer> qui soit en fait un ArrayList. B - Maintenant, on aimerait que notre méthode selection fonctionne pour des collections de n'importe quel type, plutôt que de travailler uniquement sur des Integer. On va donc paramétrer la méthode (et la rendre générique) : static <E> Collection<E> selection(Collection<E> source, CritereSelection<E> critere); Explication : Le premier <E> indique que notre méthode est paramétrée avec un nouveau type <E>, les autres indiquent qu'on retournera une collection contenant des éléments du même type que la source, et que le critère de sélection porte sur ce même type. Nous allons donc réécrire CritereSelection de la façon suivante : interface CritereSelection<E> { public boolean ok(E e); } Puis, on peut définir une classe EstMultipleDe3 de la façon suivante : class EtreMultipleDe3 implements CritereSelection<Integer> { public boolean ok(Integer n) { return n % 3 == 0; } } Réécrivez donc la méthode selection. Votre main ne devrait pas être modifié. Pour tester la généricité de votre méthode selection, dans votre main, créez une collection de Double, et un critère EstSuperieuraPI qui travaille sur des Double et retourne les éléments de la collection supérieurs à π. Utilisez la classe java.lang.Math, bien évidemment. C - Number est une classe abstraite, mère de tous les types numériques. Modifiez la classe EstSuperieuraPI pour qu'elle travaille maintenant sur des Number, afin de pouvoir lui passer des listes d'Integer ou de Double. Vous devriez obtenir une seule erreur à la compilation. Celle-ci est due au fait qu'on impose (dans le prototype de selection) que le critère porte exactement sur le même type que les éléments de source. Or, désormais, notre critère travaille sur des Number, qui sont une généralisation de Double. Dans le prototype de la méthode selection, remplacez donc : CritereSelection<E> critere par CritereSelection<? super E> critere Explication : <? super E> se traduit par « n'importe quelle généralisation (super-classe) de E ». Exemple : on possède deux critères : « tous les vertébrés qui sont venimeux » et « tous les animaux qui pèsent plus de 100g ». On peut, à juste titre, les appliquer à une collection de batraciens (car un batracien est un vertébré et un animal). Il faut donc préciser que le critère peut porter sur un type plus général que les éléments de la collection. Dans le cas qui nous occupe, on ne pourrait pas faire l'inverse (utiliser un critère portant un type plus spécialisé), par exemple sélectionner les éléments multiples de 3 d'une collection contenant des Number (car ceux-ci peuvent être des Double) et que le fait d'être multiple de 3 n'a de sens que sur des Integer. Il existe aussi <? extends E> qui se traduit par « n'importe quelle spécialisation (sous-classe) de E ». On va s'en servir dans le prochain exercice. 6.2. Transformation des éléments d'une collection A - En supposant que vous disposez d’une interface telle que : public interface Transformation { Number transfo(Number x); } écrivez une classe TestTransformation avec une méthode de signature static Collection<Number> transformation(Collection<Number> source, Transformation trans); qui renvoie la collection formée des éléments qui sont le résultat de l'application de transfo sur chaque élément de source. Écrivez une fonction main qui • crée une liste – un ArrayList, ou une LinkedList, etc. – portant des nombres entiers et doubles compris par exemple entre de 0 à 50 (des objets Integer et Double), • appelle la méthode transformation pour créer une liste de racines carrées de chacun des éléments de source. • affiche le résultat obtenu. Faites en sorte que transformation renvoie un objet de type Collection qui soit en fait un ArrayList. B - De la même manière que dans l'exercice précédent, vous aurez à modifier l'interface Transformation pour la rendre paramétrable. Créez aussi deux classes Racine et Floor qui implémentent cette interface et travaillent sur des Number. Les méthodes transfo retournent respectivement un Double et un Integer. Dans le main, vous créerez une liste d'Integer que vous transformerez grâce à Racine et une liste de Double que vous transformerez grâce à Floor. Votre méthode transformation devrait avoir le prototype suivant : static <E> Collection<E> transformation(Collection<? extends E> source, Transformation<E> trans) Expliquez pourquoi il est nécessaire de spécifier que source puisse contenir des éléments d'une sous-classe de ceux utilisés par Transformation ? C - Pour finir, on peut imaginer qu'à partir d'une liste de String, on désire obtenir une liste contenant les longueurs de ces String. Or, les types String et Integer n'ont aucune relation de parenté. Le prototype ultime de notre méthode transformation devrait être finalement le suivant : static <E, F> Collection<F> transformation(Collection<? extends E> source, Transformation<E, ? extends F> trans) Créez la classe Len (qui calcule la longueur d'une String) et modifiez le reste de votre code (les classes Floor et Racine, etc.) pour que l'ensemble de votre code fonctionne avec cette dernière mouture de transformation. Expliquez pourquoi « ? extends F » est préférable à « F » ? 6.3. Réduction des éléments d'une collection Les 2 exercices précédents implémentent les fonctions classiques map(function, iterable) et filter(function, iterable). On retrouve ces fonctions dans python2 par exemple. Il existe une troisième fonction similaire reduce(function,iterable) qui applique cumulativement une fonction (qui doit être binaire) à chaque couple d'éléments de la liste et retourne un résultat du même type que ceux des éléments de la collection. En utilisant l'interface suivante public interface Reduction<E> { E transfo(E a, E b); } écrivez un ensemble de classes et méthodes calquées sur les deux exercices précédents en appliquant une fonction somme à une collection d'entiers et la fonction concatenation à une liste de String. Pourquoi une collection pour la somme et une liste pour la concaténation ? Parce que l'addition est commutative alors que la concaténation ne l'est pas. uploads/Litterature/ exo-06.pdf
Documents similaires










-
32
-
0
-
0
Licence et utilisation
Gratuit pour un usage personnel Attribution requise- Détails
- Publié le Oct 30, 2021
- Catégorie Literature / Litté...
- Langue French
- Taille du fichier 0.1397MB