 |
 |
 |
9) Stockage des objets |
|
 |
|
Texte original |
 |
Traducteur :
Jérome Quelin |
|
 |
|
 |
 |
 |
 |
 |
 |
|
 |
|
 |
 |
 |
Exercises
|
 |
Exercices
|
 |
 |
 |
Solutions to selected exercises
can be found in the electronic document The Thinking in Java Annotated
Solution Guide, available for a small fee from
www.BruceEckel.com.
|
 |
Les solutions d'exercices sélectionnés peuvent être trouvées dans le document
électronique The Thinking in Java Annotated Solution Guide, disponible pour un faible coût
sur www.BruceEckel.com.
|
 |
 |
 |
- Create an array of
double and fill( ) it using RandDoubleGenerator. Print
the results.
- Create
a new class called Gerbil with an int gerbilNumber that’s
initialized in the constructor (similar to the Mouse example in this
chapter). Give it a method called hop( ) that prints out which
gerbil number this is, and that it’s hopping. Create an ArrayList
and add a bunch of Gerbil objects to the List. Now use the
get( ) method to move through the List and call
hop( ) for each
Gerbil.
- Modify
Exercise 2 so you use an Iterator to move through the List while
calling
hop( ).
- Take
the Gerbil class in Exercise 2 and put it into a Map instead,
associating the name of the Gerbil as a String (the key) for each
Gerbil (the value) you put in the table. Get an Iterator for the
keySet( ) and use it to move through the Map, looking up the
Gerbil for each key and printing out the key and telling the
gerbil to
hop( ).
- Create
a List (try both ArrayList and LinkedList) and fill
it using Collections2.countries. Sort the list and print it, then apply
Collections.shuffle( ) to the list repeatedly, printing it each time
so that you can see how the shuffle( ) method randomizes the list
differently each time.
- Demonstrate
that you can’t add anything but a Mouse to a
MouseList.
- Modify
MouseList.java so that it inherits from ArrayList instead of using
composition. Demonstrate the problem with this
approach.
- Repair
CatsAndDogs.java by creating a Cats container (utilizing
ArrayList) that will only accept and retrieve Cat
objects.
- Create a
container that encapsulates an array of String, and that only adds
Strings and gets Strings, so that there are no casting issues
during use. If the internal array isn’t big enough for the next add, your
container should automatically resize it. In main( ), compare the
performance of your container with an ArrayList holding
Strings.
- Repeat
Exercise 9 for a container of int, and compare the performance to an
ArrayList holding Integer objects. In your performance comparison,
include the process of incrementing each object in the
container.
- Using the
utilities in com.bruceeckel.util, create an array of each primitive type
and of String, then fill each array using an appropriate generator, and
print each array using the appropriate print( )
method.
- Create a
generator that produces character names from your favorite movies (you can use
Snow White or Star Wars as a fallback), and loops around to the
beginning when it runs out of names. Use the utilities in
com.bruceeckel.util to fill an array, an ArrayList, a
LinkedList and both types of Set, then print each
container.
- Create a
class containing two String objects, and make it Comparable so
that the comparison only cares about the first String. Fill an array and
an ArrayList with objects of your class, using the geography
generator. Demonstrate that sorting works properly. Now make a
Comparator that only cares about the second String and demonstrate
that sorting works properly; also perform a binary search using your
Comparator.
- Modify
Exercise 13 so that an alphabetic sort is
used.
- Use
Arrays2.RandStringGenerator to fill a TreeSet but using alphabetic
ordering. Print the TreeSet to verify the sort
order.
- Create both
an ArrayList and a LinkedList, and fill each using the
Collections2.capitals generator. Print each list using an ordinary
Iterator, then insert one list into the other using a
ListIterator, inserting at every other location. Now perform the
insertion starting at the end of the first list and moving
backward.
- Write a
method that uses an Iterator to step through a Collection and
print the hashCode( ) of each object in the container. Fill all the
different types of Collections with objects and apply your method to each
container.
- Repair
the problem in
InfiniteRecursion.java.
- Create
a class, then make an initialized array of objects of your class. Fill a
List from your array. Create a subset of your List using
subList( ), and then remove this subset from your List using
removeAll( ).
- Change
Exercise 6 in Chapter 7 to use an ArrayList to hold the Rodents
and an Iterator to move through the sequence of Rodents. Remember
that an ArrayList holds only Objects so you must use a cast when
accessing individual
Rodents.
- Following
the Queue.java example, create a Deque class and test
it.
- Use a
TreeMap in Statistics.java. Now add code that tests the
performance difference between HashMap and TreeMap in that
program.
- Produce a
Map and a Set containing all the countries that begin with
‘A.’
- Using
Collections2.countries, fill a Set multiple times with the same
data and verify that the Set ends up with only one of each instance. Try
this with both kinds of
Set.
- Starting
with Statistics.java, create a program that runs the test repeatedly and
looks to see if any one number tends to appear more than the others in the
results.
- Rewrite
Statistics.java using a HashSet of Counter objects
(you’ll have to modify Counter so that it will work in the
HashSet). Which approach seems
better?
- Modify the
class in Exercise 13 so that it will work with HashSets and as a key in
HashMaps.
- Using
SlowMap.java for inspiration, create a
SlowSet.
- Apply
the tests in Map1.java to SlowMap to verify that it works. Fix
anything in SlowMap that doesn’t work
correctly.
- Implement
the rest of the Map interface for
SlowMap.
- Modify
MapPerformance.java to include tests of
SlowMap.
- Modify
SlowMap so that instead of two ArrayLists, it holds a single
ArrayList of MPair objects. Verify that the modified version works
correctly. Using MapPerformance.java, test the speed of your new
Map. Now change the put( ) method so that it performs a
sort( ) after each pair is entered, and modify get( ) to
use Collections.binarySearch( ) to look up the key. Compare the
performance of the new version with the old
ones.
- Add a
char field to CountedString that is also initialized in the
constructor, and modify the hashCode( ) and equals( )
methods to include the value of this
char.
- Modify
SimpleHashMap so that it reports collisions, and test this by adding the
same data set twice so that you see
collisions.
- Modify
SimpleHashMap so that it reports the number of “probes”
necessary when collisions occur. That is, how many calls to next( )
must be made on the Iterators that walk the LinkedLists looking
for
matches?
- Implement
the clear( ) and remove( ) methods for
SimpleHashMap.
- Implement
the rest of the Map interface for
SimpleHashMap.
- Add
a private rehash( ) method to SimpleHashMap that is
invoked when the load factor exceeds 0.75. During rehashing, double the number
of buckets, then search for the first prime number greater than that to
determine the new number of
buckets.
- Following
the example in SimpleHashMap.java, create and test a
SimpleHashSet.
- Modify
SimpleHashMap to use ArrayLists instead of LinkedLists.
Modify MapPerformance.java to compare the performance of the two
implementations.
- Using
the HTML documentation for the JDK (downloadable from java.sun.com), look
up the HashMap class. Create a HashMap, fill it with elements, and
determine the load factor. Test the lookup speed with this map, then attempt to
increase the speed by making a new HashMap with a larger initial capacity
and copying the old map into the new one, running your lookup speed test again
on the new map.
- In
Chapter 8, locate the GreenhouseControls.java example, which consists of
three files. In Controller.java, the class EventSet is just a
container. Change the code to use a LinkedList instead of an
EventSet. This will require more than just replacing EventSet with
LinkedList; you’ll also need to use an Iterator to cycle
through the set of
events.
- (Challenging).
Write your own hashed map class, customized for a particular key type: String
for this example. Do not inherit it from Map. Instead, duplicate the
methods so that the put( ) and get( ) methods
specifically take String objects, not Objects, as keys. Everything
that involves keys should not use generic types, but instead work with
Strings, to avoid the cost of upcasting and downcasting. Your goal is to
make the fastest possible custom implementation. Modify
MapPerformance.java to test your implementation vs. a
HashMap.
- (Challenging).
Find the source code for List in the Java source code library that comes
with all Java distributions. Copy this code and make a special version called
intList that holds only ints. Consider what it would take to make
a special version of List for all the primitive types. Now consider what
happens if you want to make a linked list class that works with all the
primitive types. If parameterized types are ever implemented in Java, they will
provide a way to do this work for you automatically (as well as many other
benefits).
|
 |
- Créez un tableau de doubles et remplissez-le avec
fill() en utilisant RandDoubleGenerator. Affichez les
résultats.
- Créez une nouvelle classe Gerbil possédant un int
gerbilNumber initialisé dans le constructeur (similaire à l'exemple Mouse
de ce chapitre). Donnez-lui une méthode hop() qui affiche son numéro de gerboise
et un message indiquant qu'elle est en train de sauter. Créez une ArrayList et
ajoutez-y un ensemble d'objets Gerbil. Maintenant utilisez la méthode
get() pour parcourir la List et appelez hop()
pour chaque Gerbil.
- Modifiez l'exercice 2 afin d'utiliser un Iterator lors du
parcours de la List pour appeler hop().
- Prenez la classe Gerbil de l'exercice 2 et placez-la dans
une Map à la place, en associant le nom (une String) de la
Gerbil à chaque Gerbil (la valeur) stockée dans la table.
Récupérer un Iterator sur l'ensemble des clefs (obtenu via
keySet()) et utilisez-le pour parcourir la Map, récupérez la
Gerbil pour chaque clef, imprimez son nom et dites-lui de sauter avec la méthode
hop().
- Créez une List (essayez avec une
ArrayList et une LinkedList) et remplissez-la en utilisant
Collections2.countries. Triez cette liste et affichez-la, puis appliquez-lui
Collections.shuffle() plusieurs fois, en l'imprimant à chaque fois pour voir les
effets de cette méthode.
- Montrez que vous ne pouvez ajouter que des objets Mouse
dans une MouseList.
- Modifiez MouseList.java de manière à ce qu'elle hérite de
ArrayList au lieu d'utiliser la composition. Illustrez le problème de cette
approche.
- Réparez CatsAndDogs.java en créant un conteneur
Cats (en utilisant ArrayList) qui n'accepte que des objets
Cats.
- Créez un conteneur qui encapsule un tableau de Strings,
qui ne stocke et ne renvoie que des Strings, afin de ne pas avoir de transtypage à
faire lorsqu'on l'utilise. Si le tableau interne n'est pas assez grand pour l'insertion suivante,
le conteneur devra se redimensionner automatiquement. Dans main(), comparez les
performances de votre conteneur avec une ArrayList contenant des
Strings.
- Répétez l'exercice 9 pour un conteneur d'ints, et
comparez les performances avec une ArrayList contenant des objets
Integer. Dans le test de performances, incluez en plus le fait d'incrémenter
chaque objet du conteneur.
- Créez un tableau pour chaque type primitif et un tableau de
Strings, remplissez chaque tableau en utilisant un générateur fourni parmi les
utilitaires de com.bruceeckel.util, et afficher chaque tableau en utilisant la
méthode print() appropriée.
- Créez un générateur qui produise des noms de personnages de vos films
préférés (que pensez-vous de Snow White ou Star Wars), et revienne au début quand
il n'a plus de noms à proposer. Utilisez les utilitaires de com.bruceeckel.util
pour remplir un tableau, une ArrayList, une LinkedList et les
deux types de Set disponibles, puis imprimez chaque conteneur.
- Créez une classe contenant deux objets String, et
rendez-la Comparable afin que la comparaison ne porte que sur la première
String. Remplissez un tableau et une ArrayList avec des objets de
cette classe, en utilisant le générateur geography. Montrez que le tri fonctionne
correctement. Créez maintenant un Comparator qui porte sur la deuxième
String, et montrez que le tri fonctionne aussi ; effectuez une recherche en
utilisant votre Comparator.
- Modifiez l'exercice 13 afin d'utiliser un tri alphabétique.
- Utilisez Arrays2.RandStringGenerator pour remplir un
TreeSet utilisant un tri alphabétique. Imprimez le TreeSet pour
vérifier l'ordre.
- Créez une ArrayList et une LinkedList,
et remplissez-les en utilisant le générateur Collections2.capitals. Imprimez
chaque liste en utilisant un Iterator ordinaire, puis insérer une liste dans
l'autre en utilisant un ListIterator, en insérant un élément de la deuxième liste
entre chaque élément de la première liste. Réalisez maintenant cette insertion en partant de la fin
de la première liste et en la parcourant à l'envers.
- Ecrivez une méthode qui utilise un Iterator pour
parcourir une Collection et imprime le code de hachage de chaque objet du
conteneur. Remplissez tous les types de Collections existants avec des objets et
utilisez votre méthode avec chaque conteneur.
- Réparez le problème d'InfiniteRecursion.java.
- Créez une classe, puis créez un tableau d'objets de votre classe.
Remplissez une List à partir du tableau. Créez un sous-ensemble de la
List en utilisant subList(), puis supprimez cet ensemble de la
List avec removeAll().
- Modifiez l'exercice 6 du Chapitre 7 afin de stocker les
Rodents dans une ArrayList et utilisez un
Iterator pour parcourir la séquence des Rodents. Rappelez-vous
qu'une ArrayList ne stocke que des Objects et qu'on doit donc les
transtyper pour retrouver le comportement d'un Rodent.
- En vous basant sur Queue.java, créez une classe
DoubleFile et testez-la.
- Utilisez un TreeMap dans
Statistics.java. Ajoutez maintenant du code afin de tester les différences de
performances entre HashMap et TreeMap dans ce
programme.
- Créez une Map et un Set contenant tous
les pays dont le nom commence par un 'A'.
- Remplissez un Set à l'aide de
Collections2.countries, utilisez plusieurs fois les mêmes données et vérifiez que
le Set ne stocke qu'une seule instance de chaque donnée. Testez ceci avec les deux
types de Set.
- A partir de Statistics.java, créez un programme qui lance
le test plusieurs fois et vérifie si un nombre a tendance à apparaître plus souvent que les autres
dans les résultats.
- Réécrivez Statistics.java en utilisant un
HashSet d'objets Counter (vous devrez modifiez la classe
Counter afin qu'elle fonctionne avec un HashSet). Quelle approche
semble la meilleure ?
- Modifiez la classe de l'exercice 13 afin qu'elle puisse être stockée dans
un HashSet et comme clef dans un HashMap.
- Créez un SlowSet en vous inspirant de
SlowMap.java.
- Appliquez les tests de Map1.java à
SlowMap pour vérifier que cette classe fonctionne. Corrigez dans
SlowMap tout ce qui ne marche pas correctement.
- Implémentez le reste de l'interface Map pour
SlowMap.
- Modifiez MapPerformance.java afin d'inclure les tests
pour SlowMap.
- Modifiez SlowMap afin qu'elle utilise une seule
ArrayList d'objets MPair au lieu de deux
ArrayLists. Vérifiez que la version modifiée fonctionne correctement. Utilisez
MapPerformance.java pour tester cette nouvelle Map. Modifiez
maintenant la méthode put() afin qu'elle effectue un sort() après
chaque insertion, et modifiez get() afin d'utiliser
Collections.binarySearch() pour récupérer la clef. Comparez les performances de la
nouvelle version avec les anciennes.
- Ajoutez un champ char à CountedString
qui soit aussi initialisé dans le constructeur, et modifiez les méthodes
hashCode() et equals() afin d'inclure la valeur de ce
char.
- Modifiez SimpleHashMap afin de signaler les collisions,
et testez ce comportement en ajoutant les mêmes données plusieurs fois afin de voir les
collisions.
- Modifiez SimpleHashMap afin de signaler le nombre
d'objets testés lorsqu'une collision survient. Autrement dit, combien d'appels à
next() doivent être effectués sur l'Iterator parcourant la
LinkedList pour trouver l'occurence recherchée ?
- Implémentez les méthodes clear() et
remove() pour SimpleHashMap.
- Implémentez le reste de l'interface Map pour
SimpleHashMap.
- Ajoutez une méthode private rehash() à
SimpleHashMap qui soit invoquée lorsque le facteur de charge dépasse 0,75. Au
cours du rehachage, doublez le nombre de seaux et recherchez le premier nombre premier qui soit
supérieur à cette valeur pour déterminer le nouveau nombre de seaux.
- Créez et testez un SimpleHashSet en vous inspirant de
SimpleHashMap.java.
- Modifiez SimpleHashMap afin d'utiliser des
ArrayLists au lieu de LinkedLists. Modifiez
MapPerformance.java afin de comparer les performances des deux
implémentations.
- Consultez la documentation HTML du JDK (téléchargeable sur
java.sun.com) de la classe HashMap. Créez un HashMap,
remplissez-le avec des éléments et déterminez son facteur de charge. Testez la vitesse d'accès aux
éléments de ce dictionnaire ; essayez d'augmenter cette vitesse en créant un nouveau
HashMap d'une capacité initiale supérieure et en copiant l'ancien dictionnaire
dans le nouveau.
- Dans le Chapitre 8, localisez l'exemple GreenHouse.java
comportant 3 fichiers. Dans Controller.java, la classe EventSet
n'est qu'un conteneur. Changez le code afin d'utiliser une LinkedList au lieu d'un
EventSet. Remplacer EventSet par LinkedList ne
suffira pas, il vous faudra aussi utiliser un Iterator pour parcourir l'ensemble
d'événements.
- (Difficile). Créez votre propre classe de dictionnaire haché,
particularisée pour un type particulier de clefs : String par exemple. Ne la
faites pas dériver de Map. A la place, dupliquez les méthodes afin que les
méthodes put() et get() n'acceptent que des objets
String comme clef, et non des Objects. Tout ce qui touche les
clefs ne doit pas impliquer de types génériques, mais uniquement des Strings afin
d'éviter les surcoûts liés au transtypage. Votre but est de réaliser l'implémentation la plus
rapide possible. Modifiez MapPerformance.java afin de tester votre implémentation
contre un HashMap.
- (Difficile). Trouvez le code source de List dans la
bibliothèque de code source Java fournie dans toutes les distributions Java. Copiez ce code et
créez une version spéciale appelée intList qui ne stocke que des
ints. Réfléchissez à ce qu'il faudrait pour créer une version spéciale de
List pour chacun des types scalaires. Réfléchissez maintenant à ce qu'il faudrait
si on veut créer une classe de liste chaînée qui fonctionne avec tous les types scalaires. Si les
types paramétrés sont implémentés un jour dans Java, ils fourniront un moyen de réaliser ce travail
automatiquement (entre autres).
|
 |
 |
 |
[44]
It’s possible, however, to ask how big the vector is, and the
at( ) method does perform bounds checking.
|
 |
[44]Il est toutefois
possible de s'enquérir de la taille du vector, et la méthode at()
effectue, elle, un contrôle sur les indices.
|
 |
 |
 |
[45]
This is one of the places where C++ is distinctly superior to Java, since C++
supports parameterized types with the template
keyword.
|
 |
[45]C'est l'un des points
où le C++ est indiscutablement supérieur à Java, puisque le C++ supporte la notion de types
paramétrés grâce au mot-clef template.
|
 |
 |
 |
[46]
The C++ programmer will note how much the code could be collapsed with the use
of default arguments and templates. The Python programmer will note that this
entire library would be largely unnecessary in that language.
|
 |
[46]Le programmeur C++
remarquera comme le code pourrait être réduit en utilisant des arguments par defaut et des
templates. Le programmeur Python, lui, notera que cette bibliothèque est complètement inutile
dans ce langage.
|
 |
 |
 |
[47]
By Joshua Bloch at Sun.
|
 |
[47]Par Joshua Bloch de
chez Sun.
|
 |
 |
 |
[48]
This data was found on the Internet, then processed by creating a Python program
(see www.Python.org).
|
 |
[48]Ces données ont été
trouvées sur Internet, et parsées ensuite par un programme Python (cf.
www.Python.org).
|
 |
 |
 |
[49]
This is a place where operator overloading would be nice.
|
 |
[49]Voici un endroit où la
surcharge d'opérateur serait appréciée.
|
 |
 |
 |
[50]
If these speedups still don’t meet your performance needs, you can further
accelerate table lookup by writing your own Map and customizing it to
your particular types to avoid delays due to casting to and from Objects.
To reach even higher levels of performance, speed enthusiasts can use Donald
Knuth’s The Art of Computer Programming, Volume 3: Sorting and
Searching, Second Edition to replace overflow bucket lists with arrays that
have two additional benefits: they can be optimized for disk storage
characteristics and they can save most of the time of creating and garbage
collecting individual records.
|
 |
[50]Si ces accélérations
ne suffisent pas pour répondre aux besoins de performance du programme, il est toujours possible
d'accélérer les accès en implémentant une nouvelle Map et en la particularisant
pour le type spécifique destiné à être stocké pour éviter les délais dûs au transtypage en
Object et inversement. Pour atteindre des niveaux encore plus élevés de
performance, les fanas de vitesse pourront se référer à The Art of Computer Programming, Volume
3: Sorting and Searching, Second Edition de Donald Knuth pour remplacer les listes par des
tableaux qui possèdent deux avantages supplémentaires : leurs caractéristiques peuvent être
optimisées pour le stockage sur disque et ils peuvent économiser la plus grande partie du temps
passée à créer et détruire les enregistrements individuels.
|
 |
 |
 |
 |
 |
 |
 |
 |
|
 |
 |
 |
|
 |