KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > jac > util > WeakHashMap


1 /*
2  * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
3  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
4  *
5  * Modified by Renaud Pawlak to implement a weak-value map.
6  *
7  * Well, I re-used this code and changed it a little bit to fit our
8  * needs. BTW, we would have done it quite the same way if done from
9  * scratch. I don't see the point of the licence here :-p */

10
11 package org.objectweb.jac.util;
12
13 import java.lang.ref.ReferenceQueue JavaDoc;
14 import java.lang.ref.WeakReference JavaDoc;
15 import java.util.AbstractCollection JavaDoc;
16 import java.util.AbstractSet JavaDoc;
17 import java.util.ArrayList JavaDoc;
18 import java.util.Collection JavaDoc;
19 import java.util.ConcurrentModificationException JavaDoc;
20 import java.util.Iterator JavaDoc;
21 import java.util.Map.Entry;
22 import java.util.Map JavaDoc;
23 import java.util.NoSuchElementException JavaDoc;
24 import java.util.Set JavaDoc;
25 import org.apache.log4j.Logger;
26
27 /**
28  * A hashtable-based <tt>Map</tt> implementation with <em>weak
29  * values</em>. An entry in a <tt>WeakHashMap</tt> will automatically
30  * be removed when its value is no longer in ordinary use. More
31  * precisely, the presence of a mapping for a given key will not
32  * prevent the value from being discarded by the garbage collector,
33  * that is, made finalizable, finalized, and then reclaimed. When a
34  * value has been discarded its entry is effectively removed from the
35  * map, so this class behaves somewhat differently than other
36  * <tt>Map</tt> implementations.
37  *
38  * <p> Both null values and the null key are supported. This class has
39  * performance characteristics similar to those of the <tt>HashMap</tt>
40  * class, and has the same efficiency parameters of <em>initial capacity</em>
41  * and <em>load factor</em>.
42  *
43  * <p> Like most collection classes, this class is not synchronized. A
44  * synchronized <tt>WeakHashMap</tt> may be constructed using the
45  * <tt>Collections.synchronizedMap</tt> method.
46  *
47  * @author Doug Lea
48  * @author Josh Bloch
49  * @author Mark Reinhold
50  * @author Renaud Pawlak
51  * @see java.util.HashMap
52  * @see java.lang.ref.WeakReference */

53
54 public class WeakHashMap extends AbstractMap implements Map JavaDoc {
55     static Logger logger = Logger.getLogger("weak.collections");
56
57     static int hash(Object JavaDoc x) {
58         int h = x.hashCode();
59
60         h += ~(h << 9);
61         h ^= (h >>> 14);
62         h += (h << 4);
63         h ^= (h >>> 10);
64         return h;
65     }
66
67     /**
68      * The default initial capacity -- MUST be a power of two.
69      */

70     private static final int DEFAULT_INITIAL_CAPACITY = 16;
71
72     /**
73      * The maximum capacity, used if a higher value is implicitly specified
74      * by either of the constructors with arguments.
75      * MUST be a power of two <= 1<<30.
76      */

77     private static final int MAXIMUM_CAPACITY = 1 << 30;
78
79     /**
80      * The load fast used when none specified in constructor.
81      */

82     private static final float DEFAULT_LOAD_FACTOR = 0.75f;
83
84     /**
85      * The table, resized as necessary. Length MUST Always be a power of two.
86      */

87     private Entry[] table;
88
89     /**
90      * The number of key-value mappings contained in this weak hash map.
91      */

92     private int size;
93   
94     /**
95      * The next size value at which to resize (capacity * load factor).
96      */

97     private int threshold;
98   
99     /**
100      * The load factor for the hash table.
101      */

102     private final float loadFactor;
103
104     /**
105      * Reference queue for cleared WeakEntries
106      */

107     private final ReferenceQueue JavaDoc queue = new ReferenceQueue JavaDoc();
108
109     /**
110      * The number of times this HashMap has been structurally modified
111      * Structural modifications are those that change the number of mappings in
112      * the HashMap or otherwise modify its internal structure (e.g.,
113      * rehash). This field is used to make iterators on Collection-views of
114      * the HashMap fail-fast. (See ConcurrentModificationException).
115      */

116     private volatile int modCount;
117
118     /**
119      * Constructs a new, empty <tt>WeakHashMap</tt> with the given initial
120      * capacity and the given load factor.
121      *
122      * @param initialCapacity The initial capacity of the <tt>WeakHashMap</tt>
123      * @param loadFactor The load factor of the <tt>WeakHashMap</tt>
124      * @throws IllegalArgumentException If the initial capacity is negative,
125      * or if the load factor is nonpositive.
126      */

127     public WeakHashMap(int initialCapacity, float loadFactor) {
128         if (initialCapacity < 0)
129             throw new IllegalArgumentException JavaDoc("Illegal Initial Capacity: "+
130                                                initialCapacity);
131         if (initialCapacity > MAXIMUM_CAPACITY)
132             initialCapacity = MAXIMUM_CAPACITY;
133
134         if (loadFactor <= 0 || Float.isNaN(loadFactor))
135             throw new IllegalArgumentException JavaDoc("Illegal Load factor: "+
136                                                loadFactor);
137         int capacity = 1;
138         while (capacity < initialCapacity)
139             capacity <<= 1;
140         table = new Entry[capacity];
141         this.loadFactor = loadFactor;
142         threshold = (int)(capacity * loadFactor);
143     }
144
145     /**
146      * Constructs a new, empty <tt>WeakHashMap</tt> with the given initial
147      * capacity and the default load factor, which is <tt>0.75</tt>.
148      *
149      * @param initialCapacity The initial capacity of the <tt>WeakHashMap</tt>
150      * @throws IllegalArgumentException If the initial capacity is negative.
151      */

152     public WeakHashMap(int initialCapacity) {
153         this(initialCapacity, DEFAULT_LOAD_FACTOR);
154     }
155
156     /**
157      * Constructs a new, empty <tt>WeakHashMap</tt> with the default initial
158      * capacity (16) and the default load factor (0.75).
159      */

160     public WeakHashMap() {
161         this.loadFactor = DEFAULT_LOAD_FACTOR;
162         threshold = (int)(DEFAULT_INITIAL_CAPACITY);
163         table = new Entry[DEFAULT_INITIAL_CAPACITY];
164     }
165   
166     /**
167      * Constructs a new <tt>WeakHashMap</tt> with the same mappings as the
168      * specified <tt>Map</tt>. The <tt>WeakHashMap</tt> is created with
169      * default load factor, which is <tt>0.75</tt> and an initial capacity
170      * sufficient to hold the mappings in the specified <tt>Map</tt>.
171      *
172      * @param t the map whose mappings are to be placed in this map.
173      * @throws NullPointerException if the specified map is null.
174      * @since 1.3
175      */

176     public WeakHashMap(Map JavaDoc t) {
177         this(Math.max((int) (t.size() / DEFAULT_LOAD_FACTOR) + 1, 16),
178              DEFAULT_LOAD_FACTOR);
179         putAll(t);
180     }
181
182     // internal utilities
183

184     /**
185      * Value representing null keys inside tables.
186      */

187     private static final Object JavaDoc NULL_KEY = new Object JavaDoc();
188
189     /**
190      * Use NULL_KEY for key if it is null.
191      */

192     private static Object JavaDoc maskNull(Object JavaDoc key) {
193         return (key == null ? NULL_KEY : key);
194     }
195
196     /**
197      * Return internal representation of null key back to caller as null
198      */

199     private static Object JavaDoc unmaskNull(Object JavaDoc key) {
200         return (key == NULL_KEY ? null : key);
201     }
202
203     /**
204      * Check for equality of non-null reference x and possibly-null y. By
205      * default uses Object.equals.
206      */

207     static boolean eq(Object JavaDoc x, Object JavaDoc y) {
208         return x == y || x.equals(y);
209     }
210
211     /**
212      * Return index for hash code h.
213      */

214     static int indexFor(int h, int length) {
215         return h & (length-1);
216     }
217
218     /**
219      * Expunge stale entries from the table.
220      */

221     private void expungeStaleEntries() {
222         Object JavaDoc r;
223         while ( (r = queue.poll()) != null) {
224             Entry e = (Entry)r;
225             logger.debug("removing from hashmap "+r);
226
227             int h = e.hash;
228             int i = indexFor(h, table.length);
229
230             Entry prev = table[i];
231             Entry p = prev;
232             while (p != null) {
233                 Entry next = p.next;
234                 if (p == e) {
235                     if (prev == e)
236                         table[i] = next;
237                     else
238                         prev.next = next;
239                     e.next = null; // Help GC
240
e.key = null; // " "
241
size--;
242                     break;
243                 }
244                 prev = p;
245                 p = next;
246             }
247         }
248     }
249
250     /**
251      * Return the table after first expunging stale entries
252      */

253     private Entry[] getTable() {
254         expungeStaleEntries();
255         return table;
256     }
257  
258     /**
259      * Returns the number of key-value mappings in this map.
260      * This result is a snapshot, and may not reflect unprocessed
261      * entries that will be removed before next attempted access
262      * because they are no longer referenced.
263      */

264     public int size() {
265         if (size == 0)
266             return 0;
267         expungeStaleEntries();
268         return size;
269     }
270   
271     /**
272      * Returns <tt>true</tt> if this map contains no key-value mappings.
273      * This result is a snapshot, and may not reflect unprocessed
274      * entries that will be removed before next attempted access
275      * because they are no longer referenced.
276      */

277     public boolean isEmpty() {
278         return size() == 0;
279     }
280
281     /**
282      * Returns the value to which the specified key is mapped in this weak
283      * hash map, or <tt>null</tt> if the map contains no mapping for
284      * this key. A return value of <tt>null</tt> does not <i>necessarily</i>
285      * indicate that the map contains no mapping for the key; it is also
286      * possible that the map explicitly maps the key to <tt>null</tt>. The
287      * <tt>containsKey</tt> method may be used to distinguish these two
288      * cases.
289      *
290      * @param key the key whose associated value is to be returned.
291      * @return the value to which this map maps the specified key, or
292      * <tt>null</tt> if the map contains no mapping for this key.
293      * @see #put(Object, Object)
294      */

295     public Object JavaDoc get(Object JavaDoc key) {
296         Object JavaDoc k = maskNull(key);
297         int h = hash(k);
298         Entry[] tab = getTable();
299         int index = indexFor(h, tab.length);
300         Entry e = tab[index];
301         while (e != null) {
302             if (e.hash == h && eq(k, e.getKey()))
303                 return e.getValue();
304             e = e.next;
305         }
306         return null;
307     }
308   
309     /**
310      * Returns <tt>true</tt> if this map contains a mapping for the
311      * specified key.
312      *
313      * @param key The key whose presence in this map is to be tested
314      * @return <tt>true</tt> if there is a mapping for <tt>key</tt>;
315      * <tt>false</tt> otherwise
316      */

317     public boolean containsKey(Object JavaDoc key) {
318         return getEntry(key) != null;
319     }
320
321     /**
322      * Returns the entry associated with the specified key in the HashMap.
323      * Returns null if the HashMap contains no mapping for this key.
324      */

325     Entry getEntry(Object JavaDoc key) {
326         Object JavaDoc k = maskNull(key);
327         int h = hash(k);
328         Entry[] tab = getTable();
329         int index = indexFor(h, tab.length);
330         Entry e = tab[index];
331         while (e != null && !(e.hash == h && eq(k, e.get())))
332             e = e.next;
333         return e;
334     }
335
336     /**
337      * Associates the specified value with the specified key in this map.
338      * If the map previously contained a mapping for this key, the old
339      * value is replaced.
340      *
341      * @param key key with which the specified value is to be associated.
342      * @param value value to be associated with the specified key.
343      * @return previous value associated with specified key, or <tt>null</tt>
344      * if there was no mapping for key. A <tt>null</tt> return can
345      * also indicate that the HashMap previously associated
346      * <tt>null</tt> with the specified key.
347      */

348     public Object JavaDoc put(Object JavaDoc key, Object JavaDoc value) {
349         Object JavaDoc k = maskNull(key);
350         int h = hash(k);
351         Entry[] tab = getTable();
352         Object JavaDoc old = null;
353         int i = indexFor(h, tab.length);
354
355         Entry prev = tab[i];
356         Entry e = prev;
357
358         while (e != null) {
359             Entry next = e.next;
360
361             if (h == e.hash && eq(k, e.key)) {
362                 modCount++;
363                 size--;
364                 if (prev == e)
365                     tab[i] = next;
366                 else
367                     prev.next = next;
368                 old = e.getValue();
369                 break;
370             }
371
372             prev = e;
373             e = next;
374         }
375       
376         modCount++;
377         tab[i] = new Entry(k, value, queue, h, tab[i]);
378         if (++size >= threshold)
379             resize(tab.length * 2);
380         return old;
381     }
382
383     /**
384      * Rehashes the contents of this map into a new <tt>HashMap</tt> instance
385      * with a larger capacity. This method is called automatically when the
386      * number of keys in this map exceeds its capacity and load factor.
387      *
388      * Note that this method is a no-op if it's called with newCapacity ==
389      * 2*MAXIMUM_CAPACITY (which is Integer.MIN_VALUE).
390      *
391      * @param newCapacity the new capacity, MUST be a power of two.
392      */

393     void resize(int newCapacity) {
394         // assert (newCapacity & -newCapacity) == newCapacity; // power of 2
395

396         Entry[] oldTable = getTable();
397         int oldCapacity = oldTable.length;
398
399         // check if needed
400
if (size < threshold || oldCapacity > newCapacity)
401             return;
402     
403         Entry[] newTable = new Entry[newCapacity];
404
405         transfer(oldTable, newTable);
406         table = newTable;
407
408         /*
409          * If ignoring null elements and processing ref queue caused massive
410          * shrinkage, then restore old table. This should be rare, but avoids
411          * unbounded expansion of garbage-filled tables.
412          */

413         if (size >= threshold / 2) {
414             threshold = (int)(newCapacity * loadFactor);
415         } else {
416             expungeStaleEntries();
417             transfer(newTable, oldTable);
418             table = oldTable;
419         }
420     }
421
422     /** Transfer all entries from src to dest tables */
423     private void transfer(Entry[] src, Entry[] dest) {
424         for (int j = 0; j < src.length; ++j) {
425             Entry e = src[j];
426             src[j] = null;
427             while (e != null) {
428                 Entry next = e.next;
429                 Object JavaDoc key = e.get();
430                 if (key == null) {
431                     e.next = null; // Help GC
432
e.key = null; // " "
433
size--;
434                 } else {
435                     int i = indexFor(e.hash, dest.length);
436                     e.next = dest[i];
437                     dest[i] = e;
438                 }
439                 e = next;
440             }
441         }
442     }
443
444     /**
445      * Copies all of the mappings from the specified map to this map These
446      * mappings will replace any mappings that this map had for any of the
447      * keys currently in the specified map.<p>
448      *
449      * @param t mappings to be stored in this map.
450      * @throws NullPointerException if the specified map is null.
451      */

452     public void putAll(Map JavaDoc t) {
453         // Expand enough to hold t's elements without resizing.
454
int n = t.size();
455         if (n == 0)
456             return;
457         if (n >= threshold) {
458             n = (int)(n / loadFactor + 1);
459             if (n > MAXIMUM_CAPACITY)
460                 n = MAXIMUM_CAPACITY;
461             int capacity = table.length;
462             while (capacity < n)
463                 capacity <<= 1;
464             resize(capacity);
465         }
466     
467         for (Iterator JavaDoc i = t.entrySet().iterator(); i.hasNext(); ) {
468             Map.Entry JavaDoc e = (Map.Entry JavaDoc) i.next();
469             put(e.getKey(), e.getValue());
470         }
471     }
472   
473     /**
474      * Removes the mapping for this key from this map if present.
475      *
476      * @param key key whose mapping is to be removed from the map.
477      * @return previous value associated with specified key, or <tt>null</tt>
478      * if there was no mapping for key. A <tt>null</tt> return can
479      * also indicate that the map previously associated <tt>null</tt>
480      * with the specified key.
481      */

482     public Object JavaDoc remove(Object JavaDoc key) {
483         Object JavaDoc k = maskNull(key);
484         int h = hash(k);
485         Entry[] tab = getTable();
486         int i = indexFor(h, tab.length);
487         Entry prev = tab[i];
488         Entry e = prev;
489
490         while (e != null) {
491             Entry next = e.next;
492             if (h == e.hash && eq(k, e.key)) {
493                 modCount++;
494                 size--;
495                 if (prev == e)
496                     tab[i] = next;
497                 else
498                     prev.next = next;
499                 return e.getValue();
500             }
501             prev = e;
502             e = next;
503         }
504
505         return null;
506     }
507
508
509
510     /** Special version of remove needed by Entry set */
511     Entry removeMapping(Object JavaDoc o) {
512         if (!(o instanceof Map.Entry JavaDoc))
513             return null;
514         Entry[] tab = getTable();
515         Map.Entry JavaDoc entry = (Map.Entry JavaDoc)o;
516         Object JavaDoc k = maskNull(entry.getKey());
517         int h = hash(k);
518         int i = indexFor(h, tab.length);
519         Entry prev = tab[i];
520         Entry e = prev;
521
522         while (e != null) {
523             Entry next = e.next;
524             if (h == e.hash && e.equals(entry)) {
525                 modCount++;
526                 size--;
527                 if (prev == e)
528                     tab[i] = next;
529                 else
530                     prev.next = next;
531                 return e;
532             }
533             prev = e;
534             e = next;
535         }
536    
537         return null;
538     }
539
540     /**
541      * Removes all mappings from this map.
542      */

543     public void clear() {
544         // clear out ref queue. We don't need to expunge entries
545
// since table is getting cleared.
546
while (queue.poll() != null)
547             ;
548
549         modCount++;
550         Entry tab[] = table;
551         for (int i = 0; i < tab.length; ++i)
552             tab[i] = null;
553         size = 0;
554
555         // Allocation of array may have caused GC, which may have caused
556
// additional entries to go stale. Removing these entries from the
557
// reference queue will make them eligible for reclamation.
558
while (queue.poll() != null)
559             ;
560     }
561
562     /**
563      * Returns <tt>true</tt> if this map maps one or more keys to the
564      * specified value.
565      *
566      * @param value value whose presence in this map is to be tested.
567      * @return <tt>true</tt> if this map maps one or more keys to the
568      * specified value.
569      */

570     public boolean containsValue(Object JavaDoc value) {
571         if (value==null)
572             return containsNullValue();
573
574         Entry tab[] = getTable();
575         for (int i = tab.length ; i-- > 0 ;)
576             for (Entry e = tab[i] ; e != null ; e = e.next)
577                 if (value.equals(e.getValue()))
578                     return true;
579         return false;
580     }
581
582     /**
583      * Special-case code for containsValue with null argument
584      */

585     private boolean containsNullValue() {
586         Entry tab[] = getTable();
587         for (int i = tab.length ; i-- > 0 ;)
588             for (Entry e = tab[i] ; e != null ; e = e.next)
589                 if (e.getValue()==null)
590                     return true;
591         return false;
592     }
593
594     /**
595      * The entries in this hash table extend WeakReference, using its main ref
596      * field as the key.
597      */

598     private static class Entry extends WeakReference JavaDoc implements Map.Entry JavaDoc {
599         private Object JavaDoc key;
600         private final int hash;
601         private Entry next;
602
603         /**
604          * Create new entry.
605          */

606         Entry(Object JavaDoc key, Object JavaDoc value, ReferenceQueue JavaDoc queue,
607               int hash, Entry next) {
608             super(value, queue);
609             this.key = key;
610             this.hash = hash;
611             this.next = next;
612         }
613
614         public Object JavaDoc getKey() {
615             return unmaskNull(key);
616         }
617
618         public Object JavaDoc getValue() {
619             return this.get();
620         }
621     
622         public Object JavaDoc setValue(Object JavaDoc newValue) {
623             throw new RuntimeException JavaDoc(
624                 "Entry.setValue cannot be implemented in weak-value entries");
625         }
626     
627         public boolean equals(Object JavaDoc o) {
628             if (!(o instanceof Map.Entry JavaDoc))
629                 return false;
630             Map.Entry JavaDoc e = (Map.Entry JavaDoc)o;
631             Object JavaDoc k1 = getKey();
632             Object JavaDoc k2 = e.getKey();
633             if (k1 == k2 || (k1 != null && k1.equals(k2))) {
634                 Object JavaDoc v1 = getValue();
635                 Object JavaDoc v2 = e.getValue();
636                 if (v1 == v2 || (v1 != null && v1.equals(v2)))
637                     return true;
638             }
639             return false;
640         }
641     
642         public int hashCode() {
643             Object JavaDoc k = getKey();
644             Object JavaDoc v = getValue();
645             return ((k==null ? 0 : k.hashCode()) ^
646                      (v==null ? 0 : v.hashCode()));
647         }
648     
649         public String JavaDoc toString() {
650             return getKey() + "=" + getValue();
651         }
652     }
653
654     private abstract class HashIterator implements Iterator JavaDoc {
655         int index;
656         Entry entry = null;
657         Entry lastReturned = null;
658         int expectedModCount = modCount;
659
660         /**
661          * Strong reference needed to avoid disappearance of key
662          * between hasNext and next
663          */

664         Object JavaDoc nextKey = null;
665
666         /**
667          * Strong reference needed to avoid disappearance of key
668          * between nextEntry() and any use of the entry
669          */

670         Object JavaDoc currentKey = null;
671
672         HashIterator() {
673             index = (size() != 0 ? table.length : 0);
674         }
675
676         public boolean hasNext() {
677             Entry[] t = table;
678
679             while (nextKey == null) {
680                 Entry e = entry;
681                 int i = index;
682                 while (e == null && i > 0)
683                     e = t[--i];
684                 entry = e;
685                 index = i;
686                 if (e == null) {
687                     currentKey = null;
688                     return false;
689                 }
690                 nextKey = e.get(); // hold on to key in strong ref
691
if (nextKey == null)
692                     entry = entry.next;
693             }
694             return true;
695         }
696
697         /** The common parts of next() across different types of iterators */
698         protected Entry nextEntry() {
699             if (modCount != expectedModCount)
700                 throw new ConcurrentModificationException JavaDoc();
701             if (nextKey == null && !hasNext())
702                 throw new NoSuchElementException JavaDoc();
703
704             lastReturned = entry;
705             entry = entry.next;
706             currentKey = nextKey;
707             nextKey = null;
708             return lastReturned;
709         }
710
711         public void remove() {
712             if (lastReturned == null)
713                 throw new IllegalStateException JavaDoc();
714             if (modCount != expectedModCount)
715                 throw new ConcurrentModificationException JavaDoc();
716       
717             WeakHashMap.this.remove(currentKey);
718             expectedModCount = modCount;
719             lastReturned = null;
720             currentKey = null;
721         }
722
723     }
724
725     private class ValueIterator extends HashIterator {
726         public Object JavaDoc next() {
727             return nextEntry().getValue();
728         }
729     }
730
731     private class KeyIterator extends HashIterator {
732         public Object JavaDoc next() {
733             return nextEntry().getKey();
734         }
735     }
736
737     private class EntryIterator extends HashIterator {
738         public Object JavaDoc next() {
739             return nextEntry();
740         }
741     }
742
743     // Views
744

745     private transient Set JavaDoc entrySet = null;
746
747     /**
748      * Returns a set view of the keys contained in this map. The set is
749      * backed by the map, so changes to the map are reflected in the set, and
750      * vice-versa. The set supports element removal, which removes the
751      * corresponding mapping from this map, via the <tt>Iterator.remove</tt>,
752      * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt>, and
753      * <tt>clear</tt> operations. It does not support the <tt>add</tt> or
754      * <tt>addAll</tt> operations.
755      *
756      * @return a set view of the keys contained in this map.
757      */

758     /*public Set keySet() {
759       Set ks = keySet;
760       return (ks != null ? ks : (keySet = new KeySet()));
761       }
762     */

763     private class KeySet extends AbstractSet JavaDoc {
764         public Iterator JavaDoc iterator() {
765             return new KeyIterator();
766         }
767
768         public int size() {
769             return WeakHashMap.this.size();
770         }
771
772         public boolean contains(Object JavaDoc o) {
773             return containsKey(o);
774         }
775
776         public boolean remove(Object JavaDoc o) {
777             if (containsKey(o)) {
778                 WeakHashMap.this.remove(o);
779                 return true;
780             }
781             else
782                 return false;
783         }
784
785         public void clear() {
786             WeakHashMap.this.clear();
787         }
788
789         public Object JavaDoc[] toArray() {
790             Collection JavaDoc c = new ArrayList JavaDoc(size());
791             for (Iterator JavaDoc i = iterator(); i.hasNext(); )
792                 c.add(i.next());
793             return c.toArray();
794         }
795
796         public Object JavaDoc[] toArray(Object JavaDoc a[]) {
797             Collection JavaDoc c = new ArrayList JavaDoc(size());
798             for (Iterator JavaDoc i = iterator(); i.hasNext(); )
799                 c.add(i.next());
800             return c.toArray(a);
801         }
802     }
803
804     /**
805      * Returns a collection view of the values contained in this map. The
806      * collection is backed by the map, so changes to the map are reflected in
807      * the collection, and vice-versa. The collection supports element
808      * removal, which removes the corresponding mapping from this map, via the
809      * <tt>Iterator.remove</tt>, <tt>Collection.remove</tt>,
810      * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> operations.
811      * It does not support the <tt>add</tt> or <tt>addAll</tt> operations.
812      *
813      * @return a collection view of the values contained in this map.
814      */

815     public Collection JavaDoc values() {
816         Collection JavaDoc vs = values;
817         return (vs != null ? vs : (values = new Values()));
818     }
819
820     private class Values extends AbstractCollection JavaDoc {
821         public Iterator JavaDoc iterator() {
822             return new ValueIterator();
823         }
824
825         public int size() {
826             return WeakHashMap.this.size();
827         }
828
829         public boolean contains(Object JavaDoc o) {
830             return containsValue(o);
831         }
832
833         public void clear() {
834             WeakHashMap.this.clear();
835         }
836
837         public Object JavaDoc[] toArray() {
838             Collection JavaDoc c = new ArrayList JavaDoc(size());
839             for (Iterator JavaDoc i = iterator(); i.hasNext(); )
840                 c.add(i.next());
841             return c.toArray();
842         }
843
844         public Object JavaDoc[] toArray(Object JavaDoc a[]) {
845             Collection JavaDoc c = new ArrayList JavaDoc(size());
846             for (Iterator JavaDoc i = iterator(); i.hasNext(); )
847                 c.add(i.next());
848             return c.toArray(a);
849         }
850     }
851
852     /**
853      * Returns a collection view of the mappings contained in this map. Each
854      * element in the returned collection is a <tt>Map.Entry</tt>. The
855      * collection is backed by the map, so changes to the map are reflected in
856      * the collection, and vice-versa. The collection supports element
857      * removal, which removes the corresponding mapping from the map, via the
858      * <tt>Iterator.remove</tt>, <tt>Collection.remove</tt>,
859      * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> operations.
860      * It does not support the <tt>add</tt> or <tt>addAll</tt> operations.
861      *
862      * @return a collection view of the mappings contained in this map.
863      * @see java.util.Map.Entry
864      */

865     public Set JavaDoc entrySet() {
866         Set JavaDoc es = entrySet;
867         return (es != null ? es : (entrySet = new EntrySet()));
868     }
869
870     private class EntrySet extends AbstractSet JavaDoc {
871         public Iterator JavaDoc iterator() {
872             return new EntryIterator();
873         }
874
875         public boolean contains(Object JavaDoc o) {
876             if (!(o instanceof Map.Entry JavaDoc))
877                 return false;
878             Map.Entry JavaDoc e = (Map.Entry JavaDoc)o;
879             Object JavaDoc k = e.getKey();
880             Entry candidate = getEntry(e.getKey());
881             return candidate != null && candidate.equals(e);
882         }
883
884         public boolean remove(Object JavaDoc o) {
885             return removeMapping(o) != null;
886         }
887
888         public int size() {
889             return WeakHashMap.this.size();
890         }
891
892         public void clear() {
893             WeakHashMap.this.clear();
894         }
895
896         public Object JavaDoc[] toArray() {
897             Collection JavaDoc c = new ArrayList JavaDoc(size());
898             for (Iterator JavaDoc i = iterator(); i.hasNext(); )
899                 c.add(new AbstractMap.SimpleEntry((Map.Entry JavaDoc) i.next()));
900             return c.toArray();
901         }
902
903         public Object JavaDoc[] toArray(Object JavaDoc a[]) {
904             Collection JavaDoc c = new ArrayList JavaDoc(size());
905             for (Iterator JavaDoc i = iterator(); i.hasNext(); )
906                 c.add(new AbstractMap.SimpleEntry((Map.Entry JavaDoc) i.next()));
907             return c.toArray(a);
908         }
909     }
910 }
911
Popular Tags