 |
 |
9) Stockage des objets |
|
 |
|
Texte original |
 |
Traducteur : Jérome QUELIN |
|
 |
|
 |
 |
 |
 |
 |
 |
|
 |
|
 |
 |
 |
In basicTest( ) and
iterMotion( ) the calls are simply made to show the proper syntax,
and while the return value is captured, it is not used. In some cases, the
return value isn’t captured since it isn’t typically used. You
should look up the full usage of each of these methods in the online
documentation from java.sun.com before you use
them.
|
 |
basicTest() et iterMotion() sont des
procédures qui n'ont d'autre but que celui de montrer la syntaxe d'appel des méthodes dont la
valeur de retour n'est pas utilisée bien que récupérée. Dans certains cas, la valeur de retour des
méthodes n'est même pas récupérée car jamais utilisée même dans un programme réel. Se référer à la
documentation online de java.sun.com pour un examen approfondi de l'utilisation de chacune
de ces méthodes.
|
 |
 |
 |
Making a stack from a LinkedList
|
 |
Réaliser une pile à partir d'une LinkedList
|
 |
 |
 |
A stack is
sometimes referred to as a “last-in, first-out”
(LIFO) container. That is, whatever you
“push” on the stack last is the first item you can “pop”
out. Like all of the other containers in Java, what you push and pop are
Objects, so you must cast what you pop, unless you’re just using
Object behavior.
|
 |
Une pile est un conteneur « dernier arrivé, premier sorti »
(LIFO - « Last In, First Out »). C'est à dire que l'objet qu'on « pousse »
(« push »)sur la pile en dernier sera le premier accessible lors d'une extraction
(« pop »). Comme tous les autres conteneurs de Java, on stocke et récupère des
Objects, qu'il faudra donc retranstyper après leur extraction, à moins qu'on ne se
contente des fonctionnalités de la classe Object.
|
 |
 |
 |
The LinkedList has methods that
directly implement stack functionality, so you can also just use a
LinkedList rather than making a stack class. However, a stack class can
sometimes tell the story better:
|
 |
La classe LinkedList possède des méthodes qui implémentent
directement les fonctionnalités d'une pile, on peut donc utiliser directement une
LinkedList plutôt que de créer une classe implémentant une pile. Cependant une
classe est souvent plus explicite :
|
 |
 |
 |
//: c09:StackL.java // Making a stack from a LinkedList. import java.util.*; import com.bruceeckel.util.*;
public class StackL { private LinkedList list = new LinkedList(); public void push(Object v) { list.addFirst(v); } public Object top() { return list.getFirst(); } public Object pop() { return list.removeFirst(); } public static void main(String[] args) { StackL stack = new StackL(); for(int i = 0; i < 10; i++) stack.push(Collections2.countries.next()); System.out.println(stack.top()); System.out.println(stack.top()); System.out.println(stack.pop()); System.out.println(stack.pop()); System.out.println(stack.pop()); } } ///:~
|
 |
//: c09:StackL.java // Réaliser une pile à partir d'une LinkedList. import java.util.*; import com.bruceeckel.util.*;
public class StackL { private LinkedList list = new LinkedList(); public void push(Object v) { list.addFirst(v); } public Object top() { return list.getFirst(); } public Object pop() { return list.removeFirst(); } public static void main(String[] args) { StackL stack = new StackL(); for(int i = 0; i < 10; i++) stack.push(Collections2.countries.next()); System.out.println(stack.top()); System.out.println(stack.top()); System.out.println(stack.pop()); System.out.println(stack.pop()); System.out.println(stack.pop()); } } ///:~
|
 |
 |
 |
If you want only stack behavior,
inheritance is inappropriate here because it would produce a class with all the
rest of the LinkedList methods (you’ll see later that this very
mistake was made by the Java 1.0 library designers with
Stack).
|
 |
L'héritage n'est pas approprié ici puisqu'il produirait une classe
contenant toutes les méthodes d'une LinkedList (on verra que cette erreur a déjà
été faite par les concepteurs de la bibliothèque Java 1.0 avec la classe
Stack).
|
 |
 |
 |
Making a queue from a LinkedList
|
 |
Réaliser une file à partir d'une LinkedList
|
 |
 |
 |
A queue is
a “first-in, first-out” (FIFO)
container. That is, you put things in at one end, and pull them out at the
other. So the order in which you put them in will be the same order that they
come out. LinkedList has methods to support queue
behavior, so these can be used in a Queue class:
|
 |
Une file (ou queue) est un conteneur « premier arrivé, premier
sorti » (FIFO - « First In, First Out »). C'est à dire qu'on « pousse » des
objets à une extrémité et qu'on les en retire à l'autre extrémité. L'ordre dans lequel on pousse
les objets sera donc le même que l'ordre dans lequel on les récupérera. La
classe LinkedList possède des méthodes qui implémentent directement les
fonctionnalités d'une file, on peut donc les utiliser directement dans une classe
Queue :
|
 |
 |
 |
//: c09:Queue.java // Making a queue from a LinkedList. import java.util.*;
public class Queue { private LinkedList list = new LinkedList(); public void put(Object v) { list.addFirst(v); } public Object get() { return list.removeLast(); } public boolean isEmpty() { return list.isEmpty(); } public static void main(String[] args) { Queue queue = new Queue(); for(int i = 0; i < 10; i++) queue.put(Integer.toString(i)); while(!queue.isEmpty()) System.out.println(queue.get()); } } ///:~
|
 |
//: c09:Queue.java // Réaliser une file à partir d'une LinkedList. import java.util.*;
public class Queue { private LinkedList list = new LinkedList(); public void put(Object v) { list.addFirst(v); } public Object get() { return list.removeLast(); } public boolean isEmpty() { return list.isEmpty(); } public static void main(String[] args) { Queue queue = new Queue(); for(int i = 0; i < 10; i++) queue.put(Integer.toString(i)); while(!queue.isEmpty()) System.out.println(queue.get()); } } ///:~
|
 |
 |
 |
You can also easily create a deque
(double-ended queue) from a LinkedList. This is like a queue, but you can
add and remove elements from either
end.
|
 |
Il est aussi facile de créer une file double (queue à double entrée) à
partir d'une LinkedList. Une file double est une file à laquelle on peut ajouter
et supprimer des éléments à chacune de ses extrémités.
|
 |
 |
 |
Set functionality
|
 |
Fonctionnalités des Sets
|
 |
 |
 |
Set has exactly the same interface
as Collection, so there isn’t any extra functionality like there is
with the two different Lists. Instead, the Set is exactly a
Collection, it just has different behavior. (This is the ideal use of
inheritance and polymorphism: to express different behavior.) A Set
refuses to hold more than one instance of each object value (what constitutes
the “value” of an object is more complex, as you shall see).
|
 |
Les Sets ont exactement la même interface que les
Collections, et à l'inverse des deux différentes Lists, ils ne
proposent aucune fonctionnalité supplémentaire. Les Sets sont donc juste une
Collection ayant un comportement particulier (implémenter un comportement
différent constitue l'exemple type où il faut utiliser l'héritage et le polymorphisme). Un
Set refuse de contenir plus d'une instance de chaque valeur d'un objet (savoir ce
qu'est la « valeur » d'un objet est plus compliqué, comme nous allons le
voir).
|
 |
 |
 |
Set (interface)
|
Each element that you add to the
Set must be unique; otherwise the Set doesn’t add the
duplicate element. Objects added to a Set must define
equals( ) to establish object uniqueness. Set has exactly the
same interface as Collection. The Set interface does not guarantee
it will maintain its elements in any particular order.
|
HashSet*
|
For Sets where fast lookup time is
important. Objects must also define
hashCode( ).
|
TreeSet
|
An ordered Set backed by a tree.
This way, you can extract an ordered sequence from a
Set.
|
|
 |
Set (interface) |
Chaque élément ajouté au Set doit être unique ;
sinon le Set n'ajoutera pas le doublon. Les Objects ajoutés à un
Set doivent définir la méthode equals() pour pouvoir établir
l'unicité de l'objet. Un Set possède la même interface qu'une
Collection. L'interface Set ne garantit pas qu'il maintiendra les
éléments dans un ordre particulier. |
HashSet* |
Pour les Sets où le temps d'accès aux éléments est
primordial. Les Objects doivent définir la méthode
hashCode(). |
TreeSet |
Un Set trié stocké dans un arbre. De cette manière, on
peut extraire une séquence triée à partir du Set. |
|
 |
 |
 |
The following example does not
show everything you can do with a Set, since the interface is the same as
Collection, and so was exercised in the previous example. Instead, this
demonstrates the behavior that makes a Set unique:
|
 |
L'exemple suivant ne montre pas tout ce qu'il est possible de
faire avec un Set, puisque l'interface est la même que pour les
Collections, et comme telle a déjà été testée dans l'exemple précédent. Par
contre, il illustre les comportements qui rendent un Set particulier :
|
 |
 |
 |
//: c09:Set1.java // Things you can do with Sets. import java.util.*; import com.bruceeckel.util.*;
public class Set1 { static Collections2.StringGenerator gen = Collections2.countries; public static void testVisual(Set a) { Collections2.fill(a, gen.reset(), 10); Collections2.fill(a, gen.reset(), 10); Collections2.fill(a, gen.reset(), 10); System.out.println(a); // No duplicates! // Add another set to this one: a.addAll(a); a.add("one"); a.add("one"); a.add("one"); System.out.println(a); // Look something up: System.out.println("a.contains(\"one\"): " + a.contains("one")); } public static void main(String[] args) { System.out.println("HashSet"); testVisual(new HashSet()); System.out.println("TreeSet"); testVisual(new TreeSet()); } } ///:~
|
 |
//: c09:Set1.java // Opérations disponibles pour les Sets. import java.util.*; import com.bruceeckel.util.*;
public class Set1 { static Collections2.StringGenerator gen = Collections2.countries; public static void testVisual(Set a) { Collections2.fill(a, gen.reset(), 10); Collections2.fill(a, gen.reset(), 10); Collections2.fill(a, gen.reset(), 10); System.out.println(a); // Pas de doublons ! // Ajoute un autre ensemble à celui-ci : a.addAll(a); a.add("one"); a.add("one"); a.add("one"); System.out.println(a); // Extraction d'item : System.out.println("a.contains(\"one\"): " + a.contains("one")); } public static void main(String[] args) { System.out.println("HashSet"); testVisual(new HashSet()); System.out.println("TreeSet"); testVisual(new TreeSet()); } } ///:~
|
 |
 |
 |
Duplicate values are added to the
Set, but when it is printed you’ll see the Set has accepted
only one instance of each value.
|
 |
Cet exemple tente d'ajouter des valeurs dupliquées au Set,
mais lorsqu'on l'imprime on voit que le Set n'accepte qu'une instance de chaque
valeur.
|
 |
 |
 |
When you run this program you’ll
notice that the order maintained by the HashSet is different from
TreeSet, since each has a different way of storing elements so they can
be located later. (TreeSet keeps them sorted, while HashSet uses a
hashing function, which is designed specifically for rapid lookups.) When
creating your own types, be aware that a Set needs a way to maintain a
storage order, which means you must implement the Comparable interface
and define the compareTo( ) method. Here’s an
example:
|
 |
Lorsqu'on lance ce programme, on voit que l'ordre interne maintenu par le
HashSet est différent de celui de TreeSet, puisque chacune de ces
implémentations stocke les éléments d'une manière différente (TreeSet garde les
éléments triés, tandis que HashSet utilise une fonction de hachage, conçue
spécialement pour des accès optimisés). Quand on crée un nouveau type, il faut bien se rappeler
qu'un Set a besoin de maintenir un ordre de stockage, ce qui veut dire qu'il faut
implémenter l'interface Comparable et définir la méthode
compareTo(). Voici un exemple :
|
 |
 |
 |
//: c09:Set2.java // Putting your own type in a Set. import java.util.*;
class MyType implements Comparable { private int i; public MyType(int n) { i = n; } public boolean equals(Object o) { return (o instanceof MyType) && (i == ((MyType)o).i); } public int hashCode() { return i; } public String toString() { return i + " "; } public int compareTo(Object o) { int i2 = ((MyType)o).i; return (i2 < i ? -1 : (i2 == i ? 0 : 1)); } }
public class Set2 { public static Set fill(Set a, int size) { for(int i = 0; i < size; i++) a.add(new MyType(i)); return a; } public static void test(Set a) { fill(a, 10); fill(a, 10); // Try to add duplicates fill(a, 10); a.addAll(fill(new TreeSet(), 10)); System.out.println(a); } public static void main(String[] args) { test(new HashSet()); test(new TreeSet()); } } ///:~
|
 |
//: c09:Set2.java // Ajout d'un type particulier dans un Set. import java.util.*;
class MyType implements Comparable { private int i; public MyType(int n) { i = n; } public boolean equals(Object o) { return (o instanceof MyType) && (i == ((MyType)o).i); } public int hashCode() { return i; } public String toString() { return i + " "; } public int compareTo(Object o) { int i2 = ((MyType)o).i; return (i2 < i ? -1 : (i2 == i ? 0 : 1)); } }
public class Set2 { public static Set fill(Set a, int size) { for(int i = 0; i < size; i++) a.add(new MyType(i)); return a; } public static void test(Set a) { fill(a, 10); fill(a, 10); // Tente de créer des doublons fill(a, 10); a.addAll(fill(new TreeSet(), 10)); System.out.println(a); } public static void main(String[] args) { test(new HashSet()); test(new TreeSet()); } } ///:~
|
 |
 |
 |
The
form for the definitions for equals( ) and
hashCode( ) will be described later in this chapter. You must define
an equals( ) in both cases, but the hashCode( ) is
absolutely necessary only if the class will be placed in a HashSet (which
is likely, since that should generally be your first choice as a Set
implementation). However, as a programming style you should always override
hashCode( ) when you override equals( ). This process
will be fully detailed later in this chapter.
|
 |
La forme que doivent avoir les définitions des
méthodes equals() et hashCode() sera décrite plus tard dans
ce chapitre. Il faut définir une méthode equals() pour les deux implémentations de
Set, mais hashCode() n'est nécessaire que si la classe est placée
dans un hashSet (ce qui est probable, puisqu'il s'agit de l'implémentation
recommandée pour un Set). Cependant, c'est une bonne pratique de programmation de
redéfinir hashCode() lorsqu'on redéfinit equals(). Ce processus
sera examiné en détails plus loin dans ce chapitre.
|
 |
 |
 |
In the compareTo( ), note
that I did not use the “simple and obvious” form return
i-i2. Although this is a common programming error, it would only work
properly if i and i2 were “unsigned” ints (if
Java had an “unsigned” keyword, which it does not). It breaks
for Java’s signed int, which is not big enough to represent the
difference of two signed ints. If i is a large positive integer
and j is a large negative integer, i-j will overflow and return a
negative value, which will not work.
|
 |
Notez que je n'ai pas utilisé la forme « simple et
évidente » return i-i2 dans la méthode compareTo(). Bien que
ce soit une erreur de programmation classique, elle ne fonctionne que si i et
i2 sont des ints « non signés » (si Java
disposait d'un mot-clef « unsigned », ce qu'il n'a pas). Elle
ne marche pas pour les ints signés de Java, qui ne sont pas assez grands pour
représenter la différence de deux ints signés. Si i est un grand
entier positif et j un grand entier négatif, i-j débordera et
renverra une valeur négative, ce qui n'est pas le résultat attendu.
|
 |
 |
 |
SortedSet
|
 |
Sets triés : les SortedSets
|
 |
 |
 |
If you have a SortedSet (of which
TreeSet is the only one available), the elements are guaranteed to be in
sorted order which allows additional functionality to be provided with these
methods in the SortedSet interface:
|
 |
Un SortedSet (dont TreeSet est l'unique
représentant) garantit que ses éléments seront stockés triés, ce qui permet de proposer de
nouvelles fonctionnalités grâce aux méthodes supplémentaires de l'interface
SortedSet suivantes :
|
 |
 |
 |
Comparator comparator(): Produces
the Comparator used for this Set, or null for natural
ordering.
|
 |
Comparator comparator() : Renvoie le
Comparator utilisé pour ce Set, ou null dans le
cas d'un tri naturel.
|
 |
 |
 |
Object first(): Produces the
lowest element.
|
 |
Object first() : Renvoie le plus petit
élément.
|
 |
 |
 |
Object last(): Produces the
highest element.
|
 |
Object last() : Renvoie le plus grand
élément.
|
 |
 |
 |
SortedSet subSet(fromElement,
toElement): Produces a view of this Set with elements from
fromElement, inclusive, to toElement, exclusive.
|
 |
SortedSet subSet(fromElement, toElement) : Renvoie une vue
du Set contenant les éléments allant de fromElement inclus à
toElement exclu.
|
 |
 |
 |
SortedSet headSet(toElement):
Produces a view of this Set with elements less than toElement.
|
 |
SortedSet headSet(toElement) : Renvoie une vue du
Set contenant les éléments inférieurs à toElement.
|
 |
 |
 |
SortedSet tailSet(fromElement):
Produces a view of this Set with elements greater than or equal to
fromElement.
|
 |
SortedSet tailSet(fromElement): Renvoie une vue du Set contenant les éléments supérieurs ou égaux à
fromElement.
|
 |
 |
 |
Map
functionality
|
 |
Fonctionnalités des Maps
|
 |
 |
 |
An ArrayList allows you to select
from a sequence of objects using a number, so in a sense it associates numbers
to objects. But what if you’d like to select from a sequence of objects
using some other criterion? A stack is an example: its selection criterion is
“the last thing pushed on the stack.” A powerful twist on this idea
of “selecting from a sequence” is alternately termed a
map, a dictionary,
or an associative array.
Conceptually, it seems like an ArrayList, but instead of looking up
objects using a number, you look them up using another object! This is
often a key process in a program.
|
 |
Une ArrayList permet de sélectionner des éléments dans une
séquence d'objets en utilisant un nombre, elle associe donc des nombres à des objets. Mais qu'en
est-il si on souhaite sélectionner des éléments d'une séquence en utilisant un autre critère ?
Dans l'exemple d'une pile, son critère de sélection est « le dernier objet poussé sur la
pile ». Un tableau associatif, ou map,
ou dictionnaire est une alternative particulièrement puissante de cette idée de
« sélection dans une séquence ». Conceptuellement, cela ressemble à une
ArrayList, mais au lieu de sélectionner un objet par un nombre, on le sélectionne
en utilisant un autre objet ! Ce fonctionnement est d'une valeur inestimable dans un
programme.
|
 |
 |
 |
The concept shows up in Java as the
Map interface. The put(Object key, Object value) method adds a
value (the thing you want), and associates it with a key (the thing you look it
up with). get(Object key) produces the value given the corresponding key.
You can also test a Map to see if it contains a key or a value with
containsKey( ) and containsValue( ).
|
 |
Le concept est illustré dans Java via l'interface Map. La
méthode put(Object key, Object value) ajoute une valeur (la chose qu'on veut
stocker), et l'associe à une clef (la chose grâce à laquelle on va retrouver la valeur). La méthode
get(Object key) renvoie la valeur associée à la clef correspondante. Il est aussi
possible de tester une Map pour voir si elle contient une certaine clef ou une
certaine valeur avec les méthodes containsKey() et
containsValue().
|
 |
 |
 |
The standard Java library contains two
different types of Maps: HashMap and TreeMap. Both have the
same interface (since they both implement Map), but they differ in one
distinct way: efficiency. If you look at what must be done for a
get( ), it seems pretty slow to search through (for example) an
ArrayList for the key. This is where HashMap speeds things up.
Instead of a slow search for the key, it uses a special value called a
hash code. The hash code is a way to take
some information in the object in question and turn it into a “relatively
unique” int for that object. All Java objects can produce a hash
code, and hashCode( ) is a method in the root
class Object. A HashMap takes the
hashCode( ) of the object and uses it to quickly hunt for the key.
This results in a dramatic performance
improvement[50].
|
 |
La bibliothèque Java standard propose deux types de
Maps : HashMap et TreeMap. Les deux
implémentations ont la même interface (puisqu'elles implémentent toutes les deux
Map), mais diffèrent sur un point particulier : les performances. Dans le cas
d'un appel à get(), il est peu efficace de chercher dans une
ArrayList (par exemple) pour trouver une clef. C'est là que le
HashMap intervient. Au lieu d'effectuer une recherche lente sur la clef, il
utilise une valeur spéciale appelée code de hachage (hash code). Le code de
hachage est une façon d'extraire une partie de l'information de l'objet en question et de la
convertir en un int « relativement unique ». Tous les objets Java
peuvent produire un code de hachage, et hashCode() est une méthode de la
classe racine Object. Un HashMap récupère le
hashCode() de l'objet et l'utilise pour retrouver rapidement la clef. Le résultat
en est une augmentation drastique des performances [50].
|
 |
 |
 |
Map (interface)
|
Maintains key-value associations (pairs),
so you can look up a value using a key.
|
HashMap*
|
Implementation based on a hash table.
(Use this instead of Hashtable.) Provides constant-time performance for
inserting and locating pairs. Performance can be adjusted via constructors that
allow you to set the capacity and load factor of the hash
table.
|
TreeMap
|
Implementation based on a red-black tree.
When you view the keys or the pairs, they will be in sorted order (determined by
Comparable or Comparator, discussed later). The point of a
TreeMap is that you get the results in sorted order. TreeMap is
the only Map with the subMap( ) method, which allows you to
return a portion of the tree.
|
|
 |
Map (interface) |
Maintient des associations clef - valeur (des paires), afin de pouvoir
accéder à une valeur en utilisant une clef. |
HashMap* |
Implémentation basée sur une table de hachage (utilisez ceci à la place
d'une Hashtable). Fournit des performances constantes pour l'insertion et
l'extraction de paires. Les performances peuvent être ajustées via des constructeurs qui permettent
de positionner la capacité et le facteur de charge de la table de
hachage. |
TreeMap |
Implémentation basée sur un arbre rouge-noir. L'extraction des clefs ou
des paires fournit une séquence triée (selon l'ordre spécifié par Comparable ou
Comparator, comme nous le verrons plus loin). Le point important dans un
TreeMap est qu'on récupère les résultats dans l'ordre. TreeMap
est la seule Map disposant de la méthode subMap(), qui permet de
renvoyer une portion de l'arbre. |
|
 |
 |
 |
Sometimes you’ll also need to know
the details of how hashing works, so we’ll look at that a little
later.
The following example uses the
Collections2.fill( ) method and the test data sets that were
previously defined:
|
 |
Nous nous pencherons sur les mécanismes de hachage un peu plus loin.
L'exemple suivant utilise la méthode Collections2.fill() et les ensembles de
données définis précédemment :
|
 |
 |
 |
//: c09:Map1.java // Things you can do with Maps. import java.util.*; import com.bruceeckel.util.*;
public class Map1 { static Collections2.StringPairGenerator geo = Collections2.geography; static Collections2.RandStringPairGenerator rsp = Collections2.rsp; // Producing a Set of the keys: public static void printKeys(Map m) { System.out.print("Size = " + m.size() +", "); System.out.print("Keys: "); System.out.println(m.keySet()); } // Producing a Collection of the values: public static void printValues(Map m) { System.out.print("Values: "); System.out.println(m.values()); } public static void test(Map m) { Collections2.fill(m, geo, 25); // Map has 'Set' behavior for keys: Collections2.fill(m, geo.reset(), 25); printKeys(m); printValues(m); System.out.println(m); String key = CountryCapitals.pairs[4][0]; String value = CountryCapitals.pairs[4][1]; System.out.println("m.containsKey(\"" + key + "\"): " + m.containsKey(key)); System.out.println("m.get(\"" + key + "\"): " + m.get(key)); System.out.println("m.containsValue(\"" + value + "\"): " + m.containsValue(value)); Map m2 = new TreeMap(); Collections2.fill(m2, rsp, 25); m.putAll(m2); printKeys(m); key = m.keySet().iterator().next().toString(); System.out.println("First key in map: "+key); m.remove(key); printKeys(m); m.clear(); System.out.println("m.isEmpty(): " + m.isEmpty()); Collections2.fill(m, geo.reset(), 25); // Operations on the Set change the Map: m.keySet().removeAll(m.keySet()); System.out.println("m.isEmpty(): " + m.isEmpty()); } public static void main(String[] args) { System.out.println("Testing HashMap"); test(new HashMap()); System.out.println("Testing TreeMap"); test(new TreeMap()); } } ///:~
|
 |
//: c09:Map1.java // Opérations disponibles pour les Maps. import java.util.*; import com.bruceeckel.util.*;
public class Map1 { static Collections2.StringPairGenerator geo = Collections2.geography; static Collections2.RandStringPairGenerator rsp = Collections2.rsp; // Produire un Set de clefs : public static void printKeys(Map m) { System.out.print("Size = " + m.size() +", "); System.out.print("Keys: "); System.out.println(m.keySet()); } // Produire une Collection de valeurs : public static void printValues(Map m) { System.out.print("Values: "); System.out.println(m.values()); } public static void test(Map m) { Collections2.fill(m, geo, 25); // Une Map a un comportement de « Set » pour les clefs : Collections2.fill(m, geo.reset(), 25); printKeys(m); printValues(m); System.out.println(m); String key = CountryCapitals.pairs[4][0]; String value = CountryCapitals.pairs[4][1]; System.out.println("m.containsKey(\"" + key + "\"): " + m.containsKey(key)); System.out.println("m.get(\"" + key + "\"): " + m.get(key)); System.out.println("m.containsValue(\"" + value + "\"): " + m.containsValue(value)); Map m2 = new TreeMap(); Collections2.fill(m2, rsp, 25); m.putAll(m2); printKeys(m); key = m.keySet().iterator().next().toString(); System.out.println("First key in map: "+key); m.remove(key); printKeys(m); m.clear(); System.out.println("m.isEmpty(): " + m.isEmpty()); Collections2.fill(m, geo.reset(), 25); // Les opérations sur le Set changent la Map : m.keySet().removeAll(m.keySet()); System.out.println("m.isEmpty(): " + m.isEmpty()); } public static void main(String[] args) { System.out.println("Testing HashMap"); test(new HashMap()); System.out.println("Testing TreeMap"); test(new TreeMap()); } } ///:~
|
 |
 |
 |
The printKeys( ) and
printValues( ) methods are not only useful utilities, they also
demonstrate how to produce Collection views of a Map. The
keySet( ) method produces a Set backed by the keys in the
Map. Similar treatment is given to values( ), which produces
a Collection containing all the values in the Map. (Note that keys
must be unique, while values may contain duplicates.) Since these
Collections are backed by the Map, any changes in a
Collection will be reflected in the associated
Map.
|
 |
Les méthodes printKeys() et printValues()
ne sont pas seulement des utilitaires pratiques, elles illustrent aussi comment produire une vue
(sous la forme d'une Collection) d'une Map. La méthode
keySet() renvoie un Set rempli par les clefs de la
Map. La méthode values() renvoie quant à elle une
Collection contenant toutes les valeurs de la Map (notez bien que
les clefs doivent être uniques, alors que les valeurs peuvent contenir des doublons). Ces
Collections sont liées à la Map, tout changement effectué dans
une Collection sera donc répercuté dans la Map
associée.
|
 |
 |
 |
The rest of the program provides simple
examples of each Map operation, and tests each type of
Map.
|
 |
Le reste du programme fournit des exemples simples pour chacune des
opérations disponibles pour une Map, et teste les deux types de
Maps.
|
 |
 |
 |
As an example of the use of a
HashMap, consider a program to check the randomness of Java’s
Math.random( ) method.
Ideally, it would produce a perfect distribution of random numbers, but to test
this you need to generate a bunch of random numbers and count the ones that fall
in the various ranges. A HashMap is perfect for this, since it associates
objects with objects (in this case, the value object contains the number
produced by Math.random( ) along with the number of times that
number appears):
|
 |
Comme exemple d'utilisation d'un HashMap, considérons un
programme vérifiant la nature aléatoire de la méthode Math.random() de Java.
Idéalement, elle devrait produire une distribution parfaite de nombres aléatoires, mais pour tester
cela il faut générer un ensemble de nombres aléatoires et compter ceux qui tombent dans les
différentes plages. Un HashMap est parfait pour ce genre d'opérations, puisqu'il
associe des objets à d'autres objets (dans ce cas, les objets valeurs contiennent le nombre produit
par Math.random() ainsi que le nombre de fois où ce nombre
apparaît) :
|
 |
 |
 |
//: c09:Statistics.java // Simple demonstration of HashMap. import java.util.*;
class Counter { int i = 1; public String toString() { return Integer.toString(i); } }
class Statistics { public static void main(String[] args) { HashMap hm = new HashMap(); for(int i = 0; i < 10000; i++) { // Produce a number between 0 and 20: Integer r = new Integer((int)(Math.random() * 20)); if(hm.containsKey(r)) ((Counter)hm.get(r)).i++; else hm.put(r, new Counter()); } System.out.println(hm); } } ///:~
|
 |
//: c09:Statistics.java // Simple démonstration de l'utilisation d'un HashMap. import java.util.*;
class Counter { int i = 1; public String toString() { return Integer.toString(i); } }
class Statistics { public static void main(String[] args) { HashMap hm = new HashMap(); for(int i = 0; i < 10000; i++) { // Produit un nombre entre 0 et 20 : Integer r = new Integer((int)(Math.random() * 20)); if(hm.containsKey(r)) ((Counter)hm.get(r)).i++; else hm.put(r, new Counter()); } System.out.println(hm); } } ///:~
|
 |
 |
 |
 |
 |
 |
 |
 |
|
 |
 |
 |