Accueil
Java Standard Edition
Java EE 5
Visual Basic .Net 2005
Visual C++ .Net 2005
Visual C# .Net 2005
Cours ASP .Net 2.0
Postgresql
Linux
Visual Studio 2008
ASP 3.0 Classique
Cours Javascript - DOM - DHTML
Cours Ajax
VBA
Assembleur
Perl
Membres
L'auteur du site
Nouveautés sur le site
Contacts
Plan du site
Exécution d'un programme
Les archives Jar
Les classes abstraites
Les interfaces
Les tableaux
La généricité
Les énumérations
Les classes internes
Classes anonymes et internes locales
Les threads: généralités
Les threads(2): synchronisation
E/S(1):InputStream et OutputStream
E/S(2):FileInputStream et FileOutputStream
E/S(3):Reader et Writer
E/S(4):FilterInputStream et FilterOutputStream
E/S(5):Les filtres d'octets: PrintStream
E/S(6):Les filtres d'octets: DataInputStream et DataOutputStream
E/S(7):Les filtres d'octets: BufferedInputStream et BufferedOutputStream
E/S(8):Flux de caractères: PrintWriter
E/S(9):Flux de caractères: FilterReader et FilterWriter
E/S(10):Flux de caractères: InputStreamReader, OutputStreamWriter, StreamDecoder, StreamEncoder
E/S(11):Flux de caractères: BufferedReader et BufferedWriter
E/S(12):Flux de caractères: FileReader et FileWriter
La classe String (java.lang)
Les collections: L'interface Collection(java.lang)
Les collections(2): L'interface List(java.util)
Les collections(3): AbstractCollection(java.util)
Les collections(4): AbstractList(java.util)
Les collections(5): Vector(java.util)
Les collections(6): L'interface Map(java.util)
Les collections(7): AbstractMap(java.util)
Les collections(8): HashMap(java.util)
La bibliothèque Swing en Java
Les bases de données en Java
JDBC ( Java Database Connectivity )
Les interfaces graphiques
Les fichiers de configuration en Java
INSTALLATION JAVA EE 5, JRE 6, ECLIPSE, TOMCAT, ETC SOUS LINUX
INSTALLATION JAVA EE 5, JRE 6, ECLIPSE, TOMCAT, ETC SOUS WINDOWS
Les applications Web en java
Les filtres Java (javax.servlet.Filter)
I Généralités
I.1 Le formulaire principal
I.2 Les objets créés par Visual
I.3 Les variables références
I.4 Le garbage collector
II Créer évènements
II.1 Rappel évènements
II.2 Procédure à suivre
II.2.1 Créer son EventArgs
II.2.2 Créer EmetEvent
II.2.3 Déclarations autres
I Généralités
I.1 Applications winforms
I.2 Applications MFC
I.3 Objets managés ou pas
I.4 Objets non managés
I.5 Objets managés - handle
I.6 Le top-level ^
II Créer évènements
II.1 Rappel évènements
II.2 Procédure à suivre
II.2.1 Créer son EventArgs
II.2.2 Créer EmetEvent
II.2.3 Déclarations autres
I Généralités
I.1 Puissant et Accessible
I.2 Créer ses classes
II Créer évènements
II.1 Rappel évènements
II.2 Procédure à suivre
III Les services Windows
IV Le .net remoting
V Communication Tcp avec TcpClient et TcpListener
II.2.1 Créer son EventArgs
II.2.2 Créer EmetEvent
II.2.3 Déclarations autres
I Généralités
I.1 Un EDI formidable
I.2 Inclure C# ou VB
I.3 L'objet Response
I.4 Les évènements
II ASP .net et les bdd
II.1 Essayer plusieurs fois la requête
I 2.1 Fichiers distincts
I.2.2 Avec la balise script
I.2.3 Inclure réellement
I.2.4 Avec Response.Write()
I.3.1 La méthode Response.Redirect()
I.4.1 Résoudre problème post
Installation Postgre Linux
Cours Postgresql
Le Shell Unix( Linux, Ubuntu)
Les scripts C-Shell
Programmation système Unix
Reseau Linux
Les iptables
Windows Presentation Foundation(WPF)
Le Framework 3.0
Windows Workflow Foundation(WF)
ASP 3.0 Classique
Cours Javascript - DOM - DHTML
Chat Ajax
VBA Excel 2003
Assembleur
Perl
Inscription
Liste membres
Livre d'or
Forum
Accueil
>
Java Standard Edition
>
Les collections(7): AbstractMap(java.util)
____________________________________________________________________________________________________
Connexion
Les collections(7): AbstractMap(java.util)
Sommaire :
I) La classe AbstractMap (java.util)
II) L'implémentation de AbstractMap (java.util)
II-1) L'unique constructeur
II-2)entrySet(): la seule méthode abstraite
II-3)Implémentation de get(Object key)
II-4)Implémentation de remove(Object key)
II-5)Implémentation de keySet()
II-6)Implémentation de values()
II-7) Implémentation de putAll
III) Les deux classes internes statiques fournies
III-1) AbstractMap.SimpleEntry<K,V>
III-2) AbstractMap.SimpleImmutableEntry<K,V>
public abstract class AbstractMap<K,V> implements Map<K,V>
En résumé:
- C'est une implémentation minimale de l'interface Map.
- Pour les maps non modifiables, il y a juste à définir la méthode entrySet. C'est sur la seule méthode abstraite à implémenter. Ce qui signifie que l'implémentation fournie est basée complètement sur le Set retourné par cette méthode, ce qui se comprend aisément, car on n'a pas notre structure interne de données dans AbstractMap, on s'appuie donc sur ce qu'on peut pour obtenir une implémentation qui nous fournisse la fonctionnalité, même si elle n'est pas la plus efficace.
- Pour les maps modifiables, il faut, de plus, redéfinir la méthode put(qui n'est pas abstraite), qui ne peut pas être batie en s'appuyant sur une brique qu'on aurait déjà.
La méthode remove est basée sur entrySet().iterator().remove(), qui doit par conséquent être implémentée par l'itérateur du set(c'est une opération optionnelle).
I) La classe AbstractMap (java.util)
public abstract class AbstractMap<K,V> implements Map<K,V>
Elle ne fait qu'implémenter l'interface Map. C'est son unique apport.
II) L'implémentation de AbstractMap (java.util)
II-1) L'unique constructeur
Remarquons d'abord qu'il n'y a qu'un unique constructeur, sans arguments, et qui ne fait rien:
/** * Sole constructor. (For invocation by subclass constructors, typically * implicit.) */ protected AbstractMap() { }
Il n'était pas possible de fournir, à ce niveau, les constructeurs qui seront réellement utilisés par l'utilisateur de la classe. En effet, n'oublions pas que nous ne possédons pas la structure de données internes, nous ne pouvons pas faire, dans ces conditions, d'allocation dynamique de cette structure de données!
Le principe de AbstractMap, est d'utiliser le Set fourni par entrySet(). Ce Set sera utile notamment pour parcourir les valeurs de la Map. On a donc choisi de fixer un minimum à implémenter, ici cette méthode, et de baser toute l'implémentation de AbstractMap sur cette fonctionnalité minimale.
II-2)entrySet(): la seule méthode abstraite
entrySet() est la seule méthode abstraite:
public abstract Set
> entrySet();
II-3)Implémentation de get(Object key)
Tout part de la constatation qu'une map n'est rien d'autre qu'un set d'entry. Il suffit alors d'utiliser ce set équivalent dans les méthodes non implémentées de AbstractMap.
Par exemple, la méthode get(Object key):
/** * {@inheritDoc} * * <p>This implementation iterates over <tt>entrySet()</tt> searching * for an entry with the specified key. If such an entry is found, * the entry's value is returned. If the iteration terminates without * finding such an entry, <tt>null</tt> is returned. Note that this * implementation requires linear time in the size of the map; many * implementations will override this method. * * @throws ClassCastException {@inheritDoc} * @throws NullPointerException {@inheritDoc} */ public V get(Object key) { Iterator<Entry<K,V>> i = entrySet().iterator(); if (key==null) { while (i.hasNext()) { Entry<K,V> e = i.next(); if (e.getKey()==null) return e.getValue(); } } else { while (i.hasNext()) { Entry<K,V> e = i.next(); if (key.equals(e.getKey())) return e.getValue(); } } return null; }
On va se servir de l'itérateur. Un Set n'est pas ordonné, c'est pour cela qu'il n'y a pas de méthode qui permette d'accéder aux éléments, sauf iterator(), qui nous fournit un itérateur sur le set. Je ne parle pas de la méthode toArray() de Set.
On sépare le cas où la clé recherchée est null, et celui où elle ne l'est pas.
Dans le cas où elle vaut null, on parcourt les entrées du set jusqu'à trouver une clé = null. On arrête le parcours, et on retourne la valeur associée alors.
Le set est censé nous fournir un set d'entrée(Entry), qui respecte la structure des maps, c'est-à-dire qu'on ne peut pas avoir deux fois la même clé pour deux entrées (ce qui aurait été possible avec un set d'entrées). On fait donc comme si on ne pouvait pas avoir deux clés trouvées (de toutes façons on s'arrête à la première trouvée).
De même pour le cas où la clé recherchée est différente de null. On fait une boucle while sur le hasNext(). En cas de set vide, on s'arrête tout-de-suite. Sinon, on rentre dans la boucle au moins une fois. Quand on entre dans la boucle, on vérifie si l'élément est l'élément recherché ou pas. Si c'est le cas, on retourne la valeur(de type V) de l'entrée. On s'arrête dès qu'on a trouvé.
Le return null de fin est exécuté dans le cas où on n'a pas trouvé la clé.
II-4)Implémentation de remove(Object key)
Regardons à présent la méthode remove(Object key) de AbstractMap:
public V remove(Object key) { Iterator<Entry<K,V>> i = entrySet().iterator(); Entry<K,V> correctEntry = null; if (key==null) { while (correctEntry==null && i.hasNext()) { Entry<K,V> e = i.next(); if (e.getKey()==null) correctEntry = e; } } else { while (correctEntry==null && i.hasNext()) { Entry<K,V> e = i.next(); if (key.equals(e.getKey())) correctEntry = e; } } V oldValue = null; if (correctEntry !=null) { oldValue = correctEntry.getValue(); i.remove(); } return oldValue; }
Tout est aussi basé sur le iterator de entrySet(), pour les mêmes raisons que la méthode get vue ci-dessus. De plus, la suppression est basée sur le entrySet().iterator().remove().
On aurait pu aussi se servir du remove(Object o) de Set, mais c'est plus facile pour nous d'utiliser le remove de l'iterator, car on parcourt le set pour retrouver le bon objet Entry.
Et de toutes façons, si le remove de iterator est implémenté, alors le remove de Set a dû être implémenté également. Ce qui signifie que cela ne nous aurait pas soulagé de la contrainte de demander une implémentation de remove.
Le code est sur le même principe que le get: logique car on recherche la valeur à supprimer, d'après sa clé. Le correctEntry==null dans la condition des deux while, permet de sortir de la boucle dès qu'on a trouvé. Avec le get, on n'avait pas ce problème car on faisait un return.
Puis il ne reste qu'à supprimer l'entrée, si on l'a trouvé( si correctEntry !=null ), par un i.remove(). On aura gardé auparavant l'ancienne valeur de l'entrée qu'on supprime, pour la retourner( on retourne null si pas d'entrée trouvée).
II-5)Implémentation de keySet()
Voyons la méthode KeySet:
public Set<K> keySet() { if (keySet == null) { keySet = new AbstractSet<K>() { public Iterator<K> iterator() { return new Iterator<K>() { private Iterator<Entry<K,V>> i = entrySet().iterator(); public boolean hasNext() { return i.hasNext(); } public K next() { return i.next().getKey(); } public void remove() { i.remove(); } }; } public int size() { return AbstractMap.this.size(); } public boolean contains(Object k) { return AbstractMap.this.containsKey(k); } }; } return keySet; }
Cette méthode utilise un attribut privé keySet, pour gardé le key set en mémoire, s'il a déjà été construit auparavant.
transient volatile Set<K> keySet = null;
On comprend pourquoi le mettre transient: aucun intérêt de garder sa valeur lors d'une sérialisation. volatile sert à obliger la JVM à ne pas nous donner une valeur mise en cache, lorsqu'on lui demande la valeur de la propriété, et à aller chercher effectivement la valeur. Donc on est sûr
d'avoir la valeur la plus récente de la variable. Toutes les jvm ne prennent pas en compte ce mot-clé volatile. Il n'est pas beaucoup utilisé.
Le fonctionnement de keySet() est simple: si le keySet existe déjà, on retourne sa référence. Sinon, on en crée un avec une classe anonyme.
On voit ici un exemple de l'intérêt des implémentations minimales fournies par le framework, ici AbstractSet. On crée un set d'une classe anonyme héritant de AbstractSet, et dont on redéfinit les méthodes iterator(), size et contains Ces trois méthodes ne sont pas présentes du tout dans AbstractSet, elles proviennent de AbstractCollection.
size() et iterator sont abstract dans AbstractCollection. Pour contains, on le redéfinit.
La méthode iterator() se sert elle-même d'une classe anonyme qui implémente Iterator
.
Cette classe anonyme a juste en attribut privé un iterator de Entry. Tout est basé sur celui-ci.
On fait un genre de filtre: le hasnext() appelle i.hasnext(). Le remove() appelle i.remove().
Seul le next fait quelque chose de plus: il renvoie uniquement la clé, au lieu de renvoyer toute l'entrée.
On constate que notre key set se base sur notre entry set, comme structure de donnée interne.
L'entry set est d'ailleurs déclaré en attribut privé de l'itérateur.
La méthode size() de notre AbstractSet ne fait qu'appeler size() de notre AbstractMap: notre key set a le même nombre d'éléments que notre map: le nombre d'entrées, qui équivaut au nombre de clés.
La méthode contains( Object key) de notre AbstractSet, appelle juste containsKey de AbstractMap: on veut juste savoir si le set contient une clé, ce qui revient à se demander si la map contient cette clé(on sait déjà le faire).
II-6)Implémentation de values()
La méthode values est basée exactement sur le même principe que keySet.
Ici, c'est une Collection<V> qui est retournée. Et on utilise AbstractCollection, et non AbstractSet. AbstractCollection, elle-aussi, n'a que deux méthodes abstraites, size() et iterator().
public Collection<V> values() { if (values == null) { values = new AbstractCollection<V>() { public Iterator<V> iterator() { return new Iterator<V>() { private Iterator<Entry<K,V>> i = entrySet().iterator(); public boolean hasNext() { return i.hasNext(); } public V next() { return i.next().getValue(); } public void remove() { i.remove(); } }; } public int size() { return AbstractMap.this.size(); } public boolean contains(Object v) { return AbstractMap.this.containsValue(v); } }; } return values; }
L'attribut privé est celui-ci:
transient volatile Collection<V> values = null;
II-7) Implémentation de putAll
public void putAll(Map<? extends K, ? extends V> m) { for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) put(e.getKey(), e.getValue()); }
putAll fait un "foreach". Pour chaque entrée de l'entry set relative à la mappe m passée en paramètre, elle l'ajoute, par un put, dans notre map.
Tout est basé sur l'entry set de la map passée en paramètre, mais ce n'est pas pour des raisons de méthodes non implémentées, comme pour nous, puisque la map passée en paramètre possède toutes ses méthodes(c'est un objet)!
III) Les deux classes internes statiques fournies
AbstractMap nous fournit deux classes internes statiques pour nos propres besoins personnels. Elles ne sont absolument pas utilisées dans AbstractMap.
III-1) AbstractMap.SimpleEntry<K,V>
On comprend l'intérêt: dans certains cas, on doit retourner des objets Entry. Pour cela, l'interface Entry ne suffit pas. C'est par exemple le cas quand on doit implémenter la méthode Map.entrySet().toArray.
Regardons son code:
public static class SimpleEntry<K,V> implements Entry<K,V>, java.io.Serializable { private static final long serialVersionUID = -8499721149061103585L; private final K key; private V value; /** * Creates an entry representing a mapping from the specified * key to the specified value. * * @param key the key represented by this entry * @param value the value represented by this entry */ public SimpleEntry(K key, V value) { this.key = key; this.value = value; } /** * Creates an entry representing the same mapping as the * specified entry. * * @param entry the entry to copy */ public SimpleEntry(Entry<? extends K, ? extends V> entry) { this.key = entry.getKey(); this.value = entry.getValue(); } /** * Returns the key corresponding to this entry. * * @return the key corresponding to this entry */ public K getKey() { return key; } /** * Returns the value corresponding to this entry. * * @return the value corresponding to this entry */ public V getValue() { return value; } /** * Replaces the value corresponding to this entry with the specified * value. * * @param value new value to be stored in this entry * @return the old value corresponding to the entry */ public V setValue(V value) { V oldValue = this.value; this.value = value; return oldValue; } /** * Compares the specified object with this entry for equality. * Returns {@code true} if the given object is also a map entry and * the two entries represent the same mapping. More formally, two * entries {@code e1} and {@code e2} represent the same mapping * if<pre> * (e1.getKey()==null ? * e2.getKey()==null : * e1.getKey().equals(e2.getKey())) * && * (e1.getValue()==null ? * e2.getValue()==null : * e1.getValue().equals(e2.getValue()))</pre> * This ensures that the {@code equals} method works properly across * different implementations of the {@code Map.Entry} interface. * * @param o object to be compared for equality with this map entry * @return {@code true} if the specified object is equal to this map * entry * @see #hashCode */ public boolean equals(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry e = (Map.Entry)o; return eq(key, e.getKey()) && eq(value, e.getValue()); } /** * Returns the hash code value for this map entry. The hash code * of a map entry {@code e} is defined to be: <pre> * (e.getKey()==null ? 0 : e.getKey().hashCode()) ^ * (e.getValue()==null ? 0 : e.getValue().hashCode())</pre> * This ensures that {@code e1.equals(e2)} implies that * {@code e1.hashCode()==e2.hashCode()} for any two Entries * {@code e1} and {@code e2}, as required by the general * contract of {@link Object#hashCode}. * * @return the hash code value for this map entry * @see #equals */ public int hashCode() { return (key == null ? 0 : key.hashCode()) ^ (value == null ? 0 : value.hashCode()); } /** * Returns a String representation of this map entry. This * implementation returns the string representation of this * entry's key followed by the equals character ("<tt>=</tt>") * followed by the string representation of this entry's value. * * @return a String representation of this map entry */ public String toString() { return key + "=" + value; } }
La clé et la valeur sont en attributs privés. La clé est en final(ainsi elle est constante).
Il n'y a aucune difficulté dans le code.
III-2) AbstractMap.SimpleImmutableEntry<K,V>
public static class SimpleImmutableEntry<K,V> implements Entry<K,V>, java.io.Serializable
Il s'agit d'une classe représentant une entrée immuable(la clé et la valeur ne peuvent être changées). Le code est le même que SimpleEntry, excepté pour la méthode SetValue, qui déclenche une UnsupportedOperationException. Ainsi que l'attribut privée value, qui est en final.
RETOUR HAUT