Collections et généricité en Java - Jean-Claude MARTIN

La page est créée Guillaume Perrin
 
CONTINUER À LIRE
Collections et généricité en Java
Jean-Claude MARTIN

Généricité
Exemple
La généricité permet de rendre un programme plus stable en détectant certaines erreurs dès
la compilation. La généricité est très utilisée avec les collections mais peut être aussi utilisée
sans les collections.
Exemple : une boite dans laquelle on peut mettre un objet
     public class Box {
         private Object object;
         public void add(Object object) {
             this.object = object;
         }
         public Object get() {
             return object;
         }
     }

Que faire si on veut restreindre l’ajout à certains objets (par exemple des instances de
Integer) ? Un commentaire n’est pas exploitable par le compilateur :

         public class BoxDemo1 {
             public static void main(String[] args) {
                 // ONLY place Integer objects into this box!
                 Box integerBox = new Box();
                 integerBox.add(new Integer(10));
                 Integer someInteger = (Integer)integerBox.get();
                 System.out.println(someInteger);
             }
         }
Le cast est correct mais risque de provoquer une erreur si on ajoute autre chose que des
instances de Integer :

public class BoxDemo2 {

     public static void main(String[] args) {

           // ONLY place Integer objects into this box!
           Box integerBox = new Box();

           // Imagine this is one part of a large application
           // modified by one programmer.
           integerBox.add("10"); // note how the type is now String

           // ... and this is another, perhaps written
           // by a different programmer
           Integer someInteger = (Integer)integerBox.get();
           System.out.println(someInteger);
     }
}

                                                1
Exécution :
ClassCastException:
    Exception in thread "main"
         java.lang.ClassCastException:
            java.lang.String cannot be cast to java.lang.Integer
            at BoxDemo2.main(BoxDemo2.java:6)

Si la classe Box avait été conçue avec la généricité, cette erreur aurait été détectée à la
compilation.
LA GENERICITE PERMET D’EVITER DE REMPLACER CERTAINES ERREURS D’EXECUTION PAR
DES ERREURS DE COMPILATION PLUS FACILEMENT CORRIGEABLES.

Types génériques

On peut déclarer une classe générique comme suit (c’est utilisable aussi pour définir des
interfaces génériques).

/**
 * Generic version of the Box class.
 */
public class Box {

     private T t; // T stands for "Type"

     public void add(T t) {
         this.t = t;
     }

     public T get() {
         return t;
     }
}

T est une variable qui peut représenter une classe ou une interface. Ce ne peut pas être un type
de base. C’est un paramètre formel de type. Chaque occurrence de Object a été remplacée par
T.

Lors de l’utilisation de cette classe, il faut faire une invocation de type générique dans
laquelle on remplace T par une classe ou interface :

La variable T déclarée dans l’entete peut etre utilisée n’importe où dans la classe.

         Box integerBox;

Comme toute déclaration, cela ne crée pas d’objet. Cette déclaration indique juste que
intergerBox contiendra une référence à une boite contenant des objets instances de Integer.
On parle de “type paramétré”.

                                                2
Pour instancier la classe :

           integerBox = new Box();

On peut ensuite appeler des méthodes sans faire de cast :

public class BoxDemo3 {

        public static void main(String[] args) {
            Box integerBox = new Box();
            integerBox.add(new Integer(10));
            Integer someInteger = integerBox.get(); // no cast!
            System.out.println(someInteger);
        }
}

De plus, si on essaye de mettre dans box une instance d’une autre classe :

        BoxDemo3.java:5: add(java.lang.Integer) in Box
        cannot be applied to (java.lang.String)
            integerBox.add("10");
                      ^
        1 error

Attention :
        “T” ne fait pas partie du nom de la classe elle-même : seul un fichier Box.class est
         généré.
        Un type générique peut avoir plusieurs paramètres de type mais chaque paramètre
         ne peut apparaitre qu’une seule fois dans cette déclaration
         Box => erreur
         Box => permis

Generic Methods and Constructors
Type parameters can also be declared within method and constructor signatures to create
generic methods and generic constructors. This is similar to declaring a generic type, but the
type parameter's scope is limited to the method or constructor in which it's declared.
         public class Box {
             private T t;
             public void add(T t) {
                 this.t = t;
             }
             public T get() {
                 return t;
             }
             public  void inspect(U u){
                 System.out.println("T: " + t.getClass().getName());
                 System.out.println("U: " + u.getClass().getName());
             }

              public static void main(String[] args) {
                  Box integerBox = new Box();
                  integerBox.add(new Integer(10));

                                              3
integerBox.inspect("some text");
            }
       }

Here we've added one generic method, named inspect, that defines one type parameter,
named U. This method accepts an object and prints its type to standard output. For
comparison, it also prints out the type of T.
The output from this program is:
       T: java.lang.Integer
       U: java.lang.String

Bounded Type Parameters
There may be times when you'll want to restrict the kinds of types that are allowed to be
passed to a type parameter. For example, a method that operates on numbers might only
want to accept instances of Number or its subclasses.
To declare a bounded type parameter, list the type parameter's name, followed by the
extends keyword, followed by its upper bound, which in this example is Number. Note that,
in this context, extends is used in a general sense to mean either "extends" (as in classes) or
"implements" (as in interfaces).
       public class Box {
           private T t;
           public void add(T t) {
               this.t = t;
           }
           public T get() {
               return t;
           }
           public  void inspect(U u){
               System.out.println("T: " + t.getClass().getName());
               System.out.println("U: " + u.getClass().getName());
           }

           public static void main(String[] args) {
               Box integerBox = new Box();
               integerBox.add(new Integer(10));
               integerBox.inspect("some text"); // error: this is still
       String!
           }
       }

By modifying our generic method to include this bounded type parameter, compilation will
now fail, since our invocation of inspect still includes a String:
       Box.java:21: inspect(U) in Box cannot
         be applied to (java.lang.String)
                               integerBox.inspect("10");
                                          ^
       1 error

To specify additional interfaces that must be implemented, use the & character, as in:
       
                                              4
Subtyping
As you already know, it's possible to assign an object of one type to an object of another
type provided that the types are compatible. For example, you can assign an Integer to an
Object, since Object is one of Integer's supertypes:
            Object someObject = new Object();
            Integer someInteger = new Integer(10);
            someObject = someInteger; // OK

In object-oriented terminology, this is called an "is a" relationship. Since an Integer is a kind
of Object, the assignment is allowed. But Integer is also a kind of Number, so the following
code is valid as well:
            public void someMethod(Number n){
                // method body omitted
            }
            someMethod(new Integer(10)); // OK
            someMethod(new Double(10.1)); // OK

The same is also true with generics. You can perform a generic type invocation, passing
Number as its type argument, and any subsequent invocation of add will be allowed if the
argument is compatible with Number:
            Box box = new Box();
            box.add(new Integer(10)); // OK
            box.add(new Double(10.1)); // OK

Now consider the following method:
            public void boxTest(Box n){
                // method body omitted
            }

What type of argument does it accept? By looking at its signature, we can see that it accepts
a single argument whose type is Box. But what exactly does that mean? Are you
allowed to pass in Box or Box, as you might expect? Surprisingly, the
answer is "no", because Box and Box are not subtypes of Box.
Understanding why becomes much easier if you think of tangible objects — things you can
actually picture — such as a cage:
               // A cage is a collection of things, with bars to keep them in.
               interface Cage extends Collection;
A lion is a kind of animal, so Lion would be a subtype of Animal:
               interface Lion extends Animal {}
               Lion king = ...;
Where we need some animal, we're free to provide a lion:
               Animal a = king;
A lion can of course be put into a lion cage:
               Cage lionCage = ...;
               lionCage.add(king);
and a butterfly into a butterfly cage:

                                                5
interface Butterfly extends Animal {}
              Butterfly monarch = ...;
              Cage butterflyCage = ...;
              butterflyCage.add(monarch);

But what about an "animal cage"? English is ambiguous, so to be precise let's assume we're
talking about an "all-animal cage":
              Cage animalCage = ...;
This is a cage designed to hold all kinds of animals, mixed together. It must have bars strong
enough to hold in the lions, and spaced closely enough to hold in the butterflies. Such a cage
might not even be feasible to build, but if it is, then:
              animalCage.add(king);
              animalCage.add(monarch);

Since a lion is a kind of animal (Lion is a subtype of Animal), the question then becomes, "Is a
lion cage a kind of animal cage? Is Cage a subtype of Cage?". By the above
definition of animal cage, the answer must be "no". This is surprising! But it makes perfect
sense when you think about it: A lion cage cannot be assumed to keep in butterflies, and a
butterfly cage cannot be assumed to hold in lions. Therefore, neither cage can be considered
an "all-animal" cage:
       animalCage = lionCage; // compile-time error
       animalCage = butterflyCage; // compile-time error

Without generics, the animals could be placed into the wrong kinds of cages, where it would
be possible for them to escape.

Wildcards
The phrase "animal cage" can reasonably mean "all-animal cage", but it also suggests an
entirely different concept: a cage designed not for any kind of animal, but rather for some
kind of animal whose type is unknown. In generics, an unknown type is represented by the
wildcard character "?".
To specify a cage capable of holding some kind of animal:
              Cage
someCage = lionCage; // OK
               someCage = butterflyCage; // OK

So now the question becomes, "Can you add butterflies and lions directly to someCage?". As
you can probably guess, the answer to this question is "no".
               someCage.add(king);    // compiler-time error
               someCage.add(monarch); // compiler-time error

If someCage is a butterfly cage, it would hold butterflies just fine, but the lions would be able
to break free. If it's a lion cage, then all would be well with the lions, but the butterflies
would fly away. So if you can't put anything at all into someCage, is it useless? No, because
you can still read its contents:
               void feedAnimals(Cage
Summary
This chapter described the following problem: We have a Box class, written to be generally
useful so it deals with Objects. We need an instance that takes only Integers. The comments
say that only Integers go in, so the programmer knows this (or should know it), but the
compiler doesn't know it. This means that the compiler can't catch someone erroneously
adding a String. When we read the value and cast it to an Integer we'll get an exception:
       Debugging may be difficult, as the point in the code where the exception is thrown
        may be far removed from the point in the code where the error is located.
       It's always better to catch bugs when compiling than when running.
Specifically, you learned that generic type declarations can include one or more type
parameters; you supply one type argument for each type parameter when you use the
generic type. You also learned that type parameters can be used to define generic methods
and constructors. Bounded type parameters limit the kinds of types that can be passed into
a type parameter; they can specify an upper bound only. Wildcards represent unknown
types, and they can specify an upper or lower bound. During compilation, type erasure
removes all generic information from a generic class or interface, leaving behind only its raw
type.

Questions
1. Consider the following classes:
        public class AnimalHouse {
            private E animal;
            public void setAnimal(E x) {
                animal = x;
            }
            public E getAnimal() {
                return animal;
            }
        }

        public class Animal{
        }

        public class Cat extends Animal {
        }

        public class Dog extends Animal {
        }

For the following code snippets, identify whether the code:
   1.   fails to compile,
   2.   compiles with a warning,
   3.   generates an error at runtime, or
   4.   none of the above (compiles and runs without problem.)

a. AnimalHouse house = new AnimalHouse();

                                              8
b. AnimalHouse house = new AnimalHouse();

c. AnimalHouse house = new AnimalHouse();
 house.setAnimal(new Cat());

d. AnimalHouse house = new AnimalHouse();
 house.setAnimal(new Dog());

Exercises
Design a class that acts as a library for the following kinds of media: book, video, and
newspaper. Provide one version of the class that uses generics and one that does not. Feel
free to use any additional APIs for storing and retrieving the media.

Collections : définitions
Structures de données
C'est l'organisation efficace d'un ensemble de données, sous la forme de tableaux, de listes,
de piles etc. Cette efficacité réside dans la quantité mémoire utilisée pour stocker les
données, et le temps nécessaire pour réaliser des opérations sur ces données.

Collection
Une collection est un objet qui regroupe plusieurs objets. Une collection permet de stocker,
récupérer, manipuler et communiquer un ensemble de données.

Exemple
Un ensemble d’instance de la classe Contact dont chaque objet est représenté par un nom,
une adresse, un numéro de téléphone.

Framework “Collection”
A collections framework is a unified architecture for representing and manipulating
collections. All collections frameworks contain the following:
      Interfaces: These are abstract data types that represent collections. Interfaces allow
       collections to be manipulated independently of the details of their representation.
      Implementations: These are the concrete implementations of the collection
       interfaces.
      Algorithms: These are the methods that perform useful computations, such as
       searching and sorting, on objects that implement collection interfaces. The
       algorithms are said to be polymorphic: that is, the same method can be used on
       many different implementations of the appropriate collection interface.

Les interfaces du framework Collection

                                             9
   Collection: un groupe d'objets où la duplication peut-être autorisée.
      Set: est ensemble ne contenant que des valeurs et ces valeurs ne sont pas
       dupliquées. Par exemple l'ensemble A = {1,2,4,8}. Set hérite donc de Collection, mais
       n'autorise pas la duplication. SortedSet est un Set trié.
      List: hérite aussi de collection, mais autorise la duplication. Dans cette interface, un
       système d'indexation a été introduit pour permettre l'accès (rapide) aux éléments de
       la liste.
      Map: est un groupe de paires contenant une clé et une valeur associée à cette clé.
       Cette interface n'hérite ni de Set ni de Collection. La raison est que Collection traite
       des données simples alors que Map des données composées (clé,valeur). SortedMap
       est un Map trié.

Les implémentations des interfaces

Description des interfaces
L’interface Collection
       public interface Collection {
             // Basic Operations
             int size();
             boolean isEmpty();
             boolean contains(Object element);
             boolean add(Object element); // Optional
             boolean remove(Object element); // Optional
             Iterator iterator();
             int hashCode();
             boolean equals(Object element);

              // “Bulk Operations” => traite plusieurs objets
              boolean containsAll(Collection c);
              boolean addAll(Collection c); // Optional
              boolean removeAll(Collection c); // Optional
              boolean retainAll(Collection c); // Optional
              void clear(); // Optional

                                             10
// Array Operations
               Object[] toArray();
               Object[] toArray(Object a[]);
        }
Les interfaces contiennent des méthodes optionnelles. Cette approche permet de traiter les
collections particulières sans que nous soyons dans l'obligation de définir les méthodes
optionnelles. Ces méthodes optionnelles sont définies qu'en cas de besoin. Un Set non
modifiable n'a pas besoin de redéfinir la méthode add, puisque nous ne pouvons pas le
modifier!
Il y a des opérations réalisées sur un seul objet ou bien sur une collection (un ensemble
d'objets).
       add (remove) permet d'ajouter (resp. de retirer) un élément. Quand à addAll
        (removeAll) permet d'ajouter (resp. de retirer même si les éléments sont dupliqués
        dans la collection originale) une collection.
       contains (containsAll) permet de vérifier si un objet (resp. les éléments d'une
        collection) est présent dans la collection.
       size, isEmpty et clear, permettent respectivement de donner la taille de la collection,
        de vérifier si la collection est vide et finalement d'effacer le contenu de la collection.
       retainsAll se comporte comme le résultat de l'intersection de deux ensembles. Si
        A={1,2,5,8} et B={3,8} alors A = {8}.
       equals permet de tester si deux objets sont égaux.
       hashCode retourne le code de hachage calculé pour la collection.
       toArray retourne les éléments de la collection sous le format d'un tableau.
       toArray(Object a[]) permet de préciser le type du tableau à retourner. Si le tableau
        est grand les éléments sont rangés dans ce tableau, sinon un nouveau tableau est
        crée pour recevoir les éléments de la collection.

L’interface Iterator
C'est l'outil utilisé pour parcourir une collection.
        public interface Iterator {
              boolean hasNext();
              Object next();
              void remove(); // Optional
        }
       hasNext permet de vérifier s'il y a un élément qui suit.
       next permet de pointer l'élément suivant.
       remove permet de retirer l'élément courant.

Exemple :
        Collection collection = … ;   // new d’une classe qui
                                            //implémente Collection
        Iterator iterator = collection.iterator();
        while (iterator.hasNext()) {
              Object element = iterator.next();
              if (aSupprimer(element)) {
                    iterator.remove();
              }
        }

                                                 11
Enfin, les collections vues comme des ensembles réalisent les 3 opérations mathématiques
sur des ensembles:
      union : add et addAll
      intersection : retainAll
      différence : remove et removeAll

L’interface Set
C'est une interface identique à celle de Collection. Les éléments ne peuvent pas être
duppliqués. Deux implémentations possibles:
      TreeSet: les éléments sont rangés de manière ascendante.
      HashSet: les éléments sont rangés suivant une méthode de hachage.
       import java.util.*;
       public class SetExample {
             public static void main(String args[]) {
                   Set set = new HashSet(); // Une table de Hachage
                   set.add("Bernadine");
                   set.add("Elizabeth");
                   set.add("Gene");
                   set.add("Elizabeth");
                   set.add("Clara");
                   System.out.println(set);
                   Set sortedSet = new TreeSet(set); // Un Set trié
                   System.out.println(sortedSet);
             }
       }
       EXECUTION :
       [Gene, Clara, Bernadine, Elizabeth]
       [Bernadine, Clara, Elizabeth, Gene]

L’interface List
Liste est une collection ordonnée. Elle permet la duplication des éléments. L'interface est
renforcée par des méthodes permettant d'ajouter ou de retirer des éléments se trouvant à
une position donnée. Elle permet aussi de travailler sur des sous-listes. On utilise le plus
souvent des ArrayList sauf s'il y a insertion d'élément(s) au milieu de la liste. Dans ce cas il
est préférable d'utiliser une LinkedList pour éviter ainsi les décalages.

       public interface List extends Collection {
             // Positional Access
             Object get(int index);
             Object set(int index, Object element); // Optional
             void add(int index, Object element); // Optional
             Object remove(int index); // Optional
             boolean addAll(int index, Collection c); // Optional

              // Search
              int indexOf(Object o);
              int lastIndexOf(Object o);

              // Iteration
              ListIterator listIterator();
              ListIterator listIterator(int index);

                                              12
// Range-view
               List subList(int fromIndex, int toIndex);
       }

Les méthodes de l'interface List permettent d'agir sur un élément se trouvant à un index
donné ou bien un ensemble d'éléments à partir d'un index donné dans la liste.
      get (remove) retourne (resp. retirer) l'élément se trouvant à la position index.
      set (add & addAll) modifie (resp. ajouter) l'élément (resp. un seul ou une collection)
       se trouvant à la position index.
      indexOf (lastIndexOf) recherche si un objet se trouve dans la liste et retourner son
       (resp. son dernier) index.
      subList permet de créer un sous liste d'une liste.

Pour parcourir une liste, il a été défini un itérateur spécialement pour la liste.
       public interface ListIterator extends Iterator {
             boolean hasNext();
             Object next();
             boolean hasPrevious();
             Object previous();
             int nextIndex();
             int previousIndex();
             void remove(); // Optional
             void set(Object o); // Optional
             void add(Object o); // Optional
       }

permet donc de parcourir la liste dans les deux directions et de modifier un élément (set) ou
d'ajouter un nouveau élément.
       List list = ...;
       ListIterator iterator = list.listIterator(list.size());
       while (iterator.hasPrevious()) {
             Object element = iterator.previous();
             // traitement d'un élément
       }

      hasNext permet de vérifier s'il y a un élément qui suit.
      next permet de pointer l'élément courant.
      nextIndex retourne l'index de l'élément courant.
Pour les sous listes, elles sont extraites des listes de fromIndex (inclus) à toIndex (non inclus).
Tout changement sur les sous listes affecte la liste de base, et l'inverse provoque un état
indéfini s'il y a accès à la sous liste.

       import java.util.*;
       public class ListExample {
             public static void main(String args[]) {
                   List list = new ArrayList();
                   list.add("Bernadine");
                   list.add("Elizabeth");
                   list.add("Gene");

                                                13
list.add("Elizabeth");
                     list.add("Clara");
                     System.out.println(list);
                     System.out.println("2: " + list.get(2));
                     System.out.println("0: " + list.get(0));
                     LinkedList queue = new LinkedList();
                     queue.addFirst("Bernadine");
                     queue.addFirst("Elizabeth");
                     queue.addFirst("Gene");
                     queue.addFirst("Elizabeth");
                     queue.addFirst("Clara");
                     System.out.println(queue);
                     queue.removeLast();
                     queue.removeLast();
                     System.out.println(queue);
             }
       }
       EXECUTION
       Bernadine, Elizabeth, Gene, Elizabeth, Clara]
       2: Gene
       0: Bernadine
       [Clara, Elizabeth, Gene, Elizabeth, Bernadine]
       [Clara, Elizabeth, Gene]

L’interface Map
C'est un ensemble de paires, contenant une clé et une valeur.
Deux clés ne peuvent être égales au sens de equals.
L'interface interne Entry permet de manipuler les éléments d'une paire comme suit:
       public interface Entry {
             Object getKey();
             Object getValue();
             Object setValue(Object value);
       }
      getKey & getValue retournent respectivement la clé et la valeur associée à cette clé.
      setValue permet de modifier une valeur d'une paire. Remarque: faire attention de ne
       pas modifier directement la valeur associée à une clé. Pour le faire, retirer l'ancienne
       clé (et donc sa valeur aussi) et ajouter une nouvelle clé (avec cette nouvelle valeur).

       public interface Map {
             // Basic Operations
             Object put(Object key, Object value);
             Object get(Object key);
             Object remove(Object key);
             boolean containsKey(Object key);
             boolean containsValue(Object value);
             int size();
             boolean isEmpty();

              // Bulk Operations
              void putAll(Map t);
              void clear();

              // Collection Views
              public Set keySet();
              public Collection values();
              public Set entrySet();

                                             14
// Interface for entrySet elements
              public interface Entry {
              Object getKey();
              Object getValue();
              Object setValue(Object value);
              }
       }
      values retourne les valeurs sous la forme d’une Collection.
      keySet et entrySet retournent, respectivement, un ensemble (Set) de clés et un
       ensemble (set) d'Entry.
Ceci permet donc d'itérer sur les Map comme suit:
si m est un HashMap alors:
       // sur les clés
       for (Iterator i = m.keySet().iterator();i.hasNext();)
             System.out.println(i.next());

       // sur les valeurs
       for (Iterator i = m.values().iterator();i.hasNext();)
             System.out.println(i.next());

       // sur la paire clé/valeur
       for (Iterator i = m.keySet().iterator();i.hasNext();){
             Map.Entry e = (Map.Entry) i.next();
             System.out.println(e.getKey() + " ; " + e.getValue());
       }

       import java.util.*;
       public class MapExample {
       public static void main(String args[]) {
             Map map = new HashMap();
             Integer ONE = new Integer(1);
             for (int i=0, n=args.length; i
Trier:
        sort(List list) ; trie une liste.
        sort(List list,Comparator comp) ; trie une liste en utilisant un comparateur.

Mélanger:
        shuffle(List liste) ; mélange les éléments de manière aléatoire.

Manipuler:
        reverse(List liste) ; inverse les éléments de la liste.
        fill (List liste, Object element) ; initialise les éléments de la liste avec element.
        copy(List dest, List src) ; copy une liste src dans une liste dest.

Rechercher:
        binarySearch(List list, Object element) ; une recherche binaire d'un élément.
        binarySearch(List list, Object element, Comparator comp) ; une recherche binaire
         d'un élément en utilisant un comparateur.

Effectuer des recherches extrêmes:
        min (Collection)
        max (Collection)

L’interface Comparable
Un algorithme extrêmement rapide et stable (les éléments équivalents ne sont pas
réordonnés) est utilisé pour trier la liste en utilisant l'ordre naturel du type. Le tri ne peut
avoir lieu que si les classes implantent la méthode Comparable, ce qui n'est toujours pas le
cas2. Cette classe contient une seule méthode compareTo:
         interface Comparable {
               int compareTo(Object obj);
         }
Cette méthode retourne:
        entier positif si l'objet qui fait l'appel est plus grand que obj,
        zéro s'ils sont identiques,
        négatif si l'objet qui fait l'appel est plus petit que obj.

Dans le cas d'une classe qui n'implante pas la classe Comparable, ou bien vous voulez
spécifier un autre ordre, vous devez implanter l'interface Comparator. Cette dernière
permet de comparer deux éléments de la collection. Pour trier, nous passons une instance
de cette classe à la méthode Sort().
         interface Comparator {
               int compare(Object o1, Object o2);
               boolean equals(Object object);

                                                  16
}
       class CaseInsensitiveComparator implements Comparator {
             public int compare(Object element1,Object element2) {
                   String lowerE1 = (
                   (String)element1).toLowerCase();
                   String lowerE2 = (
                   (String)element2).toLowerCase();
                   return lowerE1.compareTo(lowerE2);
             }
       }

Généricité et collections
Toutes les interfaces collection sont génériques. L’interface Collection est déclarée ainsi :
       public interface Collection...

La syntaxe  indique que l’interface est générique. Quand on déclare une instance de
Collection, il est fortement conseillé de spécifier le type d’objet qui sera contenu dans la
collection. Cela permet au compilateur de vérifier que le type d’objet ajouté est correct et
permet ainsi de diminuer les erreurs d’exécution.

Bibliographie
   http://www.iro.umontreal.ca/~lokbani/cours/ift1176/communs/Cours/PDF/Collections.
    pdf
   http://java.sun.com/docs/books/tutorial/collections/index.html
   http://java.sun.com/docs/books/tutorial/java/generics/index.html


                                               17
Vous pouvez aussi lire