Source Code Cross Referenced for ReferenceMap.java in  » Library » Apache-common-Collections » org » apache » commons » collections » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Library » Apache common Collections » org.apache.commons.collections 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         *  Copyright 2001-2004 The Apache Software Foundation
003:         *
004:         *  Licensed under the Apache License, Version 2.0 (the "License");
005:         *  you may not use this file except in compliance with the License.
006:         *  You may obtain a copy of the License at
007:         *
008:         *      http://www.apache.org/licenses/LICENSE-2.0
009:         *
010:         *  Unless required by applicable law or agreed to in writing, software
011:         *  distributed under the License is distributed on an "AS IS" BASIS,
012:         *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013:         *  See the License for the specific language governing permissions and
014:         *  limitations under the License.
015:         */
016:        package org.apache.commons.collections;
017:
018:        import java.io.IOException;
019:        import java.io.ObjectInputStream;
020:        import java.io.ObjectOutputStream;
021:        import java.lang.ref.Reference;
022:        import java.lang.ref.ReferenceQueue;
023:        import java.lang.ref.SoftReference;
024:        import java.lang.ref.WeakReference;
025:        import java.util.AbstractCollection;
026:        import java.util.AbstractMap;
027:        import java.util.AbstractSet;
028:        import java.util.ArrayList;
029:        import java.util.Arrays;
030:        import java.util.Collection;
031:        import java.util.ConcurrentModificationException;
032:        import java.util.Iterator;
033:        import java.util.Map;
034:        import java.util.NoSuchElementException;
035:        import java.util.Set;
036:
037:        import org.apache.commons.collections.keyvalue.DefaultMapEntry;
038:
039:        /**
040:         *  Hash-based {@link Map} implementation that allows
041:         *  mappings to be removed by the garbage collector.<p>
042:         *
043:         *  When you construct a <code>ReferenceMap</code>, you can 
044:         *  specify what kind of references are used to store the
045:         *  map's keys and values.  If non-hard references are 
046:         *  used, then the garbage collector can remove mappings
047:         *  if a key or value becomes unreachable, or if the 
048:         *  JVM's memory is running low.  For information on how
049:         *  the different reference types behave, see
050:         *  {@link Reference}.<p>
051:         *
052:         *  Different types of references can be specified for keys
053:         *  and values.  The keys can be configured to be weak but
054:         *  the values hard, in which case this class will behave
055:         *  like a <a href="http://java.sun.com/j2se/1.4/docs/api/java/util/WeakHashMap.html">
056:         *  <code>WeakHashMap</code></a>.  However, you
057:         *  can also specify hard keys and weak values, or any other
058:         *  combination.  The default constructor uses hard keys
059:         *  and soft values, providing a memory-sensitive cache.<p>
060:         *
061:         *  The algorithms used are basically the same as those
062:         *  in {@link java.util.HashMap}.  In particular, you 
063:         *  can specify a load factor and capacity to suit your
064:         *  needs.  All optional {@link Map} operations are 
065:         *  supported.<p>
066:         *
067:         *  However, this {@link Map} implementation does <I>not</I>
068:         *  allow null elements.  Attempting to add a null key or
069:         *  or a null value to the map will raise a 
070:         *  <code>NullPointerException</code>.<p>
071:         *
072:         *  As usual, this implementation is not synchronized.  You
073:         *  can use {@link java.util.Collections#synchronizedMap} to 
074:         *  provide synchronized access to a <code>ReferenceMap</code>.
075:         *
076:         * @see java.lang.ref.Reference
077:         * 
078:         * @deprecated Moved to map subpackage. Due to be removed in v4.0.
079:         * @since Commons Collections 2.1
080:         * @version $Revision: 348444 $ $Date: 2005-11-23 14:06:56 +0000 (Wed, 23 Nov 2005) $
081:         * 
082:         * @author Paul Jack
083:         */
084:        public class ReferenceMap extends AbstractMap {
085:
086:            /**
087:             *  For serialization.
088:             */
089:            private static final long serialVersionUID = -3370601314380922368L;
090:
091:            /**
092:             *  Constant indicating that hard references should be used.
093:             */
094:            final public static int HARD = 0;
095:
096:            /**
097:             *  Constant indicating that soft references should be used.
098:             */
099:            final public static int SOFT = 1;
100:
101:            /**
102:             *  Constant indicating that weak references should be used.
103:             */
104:            final public static int WEAK = 2;
105:
106:            // --- serialized instance variables:
107:
108:            /**
109:             *  The reference type for keys.  Must be HARD, SOFT, WEAK.
110:             *  Note: I originally marked this field as final, but then this class
111:             *   didn't compile under JDK1.2.2.
112:             *  @serial
113:             */
114:            private int keyType;
115:
116:            /**
117:             *  The reference type for values.  Must be HARD, SOFT, WEAK.
118:             *  Note: I originally marked this field as final, but then this class
119:             *   didn't compile under JDK1.2.2.
120:             *  @serial
121:             */
122:            private int valueType;
123:
124:            /**
125:             *  The threshold variable is calculated by multiplying
126:             *  table.length and loadFactor.  
127:             *  Note: I originally marked this field as final, but then this class
128:             *   didn't compile under JDK1.2.2.
129:             *  @serial
130:             */
131:            private float loadFactor;
132:
133:            /**
134:             * Should the value be automatically purged when the associated key has been collected?
135:             */
136:            private boolean purgeValues = false;
137:
138:            // -- Non-serialized instance variables
139:
140:            /**
141:             *  ReferenceQueue used to eliminate stale mappings.
142:             *  See purge.
143:             */
144:            private transient ReferenceQueue queue = new ReferenceQueue();
145:
146:            /**
147:             *  The hash table.  Its length is always a power of two.  
148:             */
149:            private transient Entry[] table;
150:
151:            /**
152:             *  Number of mappings in this map.
153:             */
154:            private transient int size;
155:
156:            /**
157:             *  When size reaches threshold, the map is resized.  
158:             *  See resize().
159:             */
160:            private transient int threshold;
161:
162:            /**
163:             *  Number of times this map has been modified.
164:             */
165:            private transient volatile int modCount;
166:
167:            /**
168:             *  Cached key set.  May be null if key set is never accessed.
169:             */
170:            private transient Set keySet;
171:
172:            /**
173:             *  Cached entry set.  May be null if entry set is never accessed.
174:             */
175:            private transient Set entrySet;
176:
177:            /**
178:             *  Cached values.  May be null if values() is never accessed.
179:             */
180:            private transient Collection values;
181:
182:            /**
183:             *  Constructs a new <code>ReferenceMap</code> that will
184:             *  use hard references to keys and soft references to values.
185:             */
186:            public ReferenceMap() {
187:                this (HARD, SOFT);
188:            }
189:
190:            /**
191:             *  Constructs a new <code>ReferenceMap</code> that will
192:             *  use the specified types of references.
193:             *
194:             *  @param keyType  the type of reference to use for keys;
195:             *   must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
196:             *  @param valueType  the type of reference to use for values;
197:             *   must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
198:             *  @param purgeValues should the value be automatically purged when the 
199:             *   key is garbage collected 
200:             */
201:            public ReferenceMap(int keyType, int valueType, boolean purgeValues) {
202:                this (keyType, valueType);
203:                this .purgeValues = purgeValues;
204:            }
205:
206:            /**
207:             *  Constructs a new <code>ReferenceMap</code> that will
208:             *  use the specified types of references.
209:             *
210:             *  @param keyType  the type of reference to use for keys;
211:             *   must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
212:             *  @param valueType  the type of reference to use for values;
213:             *   must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
214:             */
215:            public ReferenceMap(int keyType, int valueType) {
216:                this (keyType, valueType, 16, 0.75f);
217:            }
218:
219:            /**
220:             *  Constructs a new <code>ReferenceMap</code> with the
221:             *  specified reference types, load factor and initial
222:             *  capacity.
223:             *
224:             *  @param keyType  the type of reference to use for keys;
225:             *   must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
226:             *  @param valueType  the type of reference to use for values;
227:             *   must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
228:             *  @param capacity  the initial capacity for the map
229:             *  @param loadFactor  the load factor for the map
230:             *  @param purgeValues should the value be automatically purged when the 
231:             *   key is garbage collected 
232:             */
233:            public ReferenceMap(int keyType, int valueType, int capacity,
234:                    float loadFactor, boolean purgeValues) {
235:                this (keyType, valueType, capacity, loadFactor);
236:                this .purgeValues = purgeValues;
237:            }
238:
239:            /**
240:             *  Constructs a new <code>ReferenceMap</code> with the
241:             *  specified reference types, load factor and initial
242:             *  capacity.
243:             *
244:             *  @param keyType  the type of reference to use for keys;
245:             *   must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
246:             *  @param valueType  the type of reference to use for values;
247:             *   must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
248:             *  @param capacity  the initial capacity for the map
249:             *  @param loadFactor  the load factor for the map
250:             */
251:            public ReferenceMap(int keyType, int valueType, int capacity,
252:                    float loadFactor) {
253:                super ();
254:
255:                verify("keyType", keyType);
256:                verify("valueType", valueType);
257:
258:                if (capacity <= 0) {
259:                    throw new IllegalArgumentException(
260:                            "capacity must be positive");
261:                }
262:                if ((loadFactor <= 0.0f) || (loadFactor >= 1.0f)) {
263:                    throw new IllegalArgumentException(
264:                            "Load factor must be greater than 0 and less than 1.");
265:                }
266:
267:                this .keyType = keyType;
268:                this .valueType = valueType;
269:
270:                int v = 1;
271:                while (v < capacity)
272:                    v *= 2;
273:
274:                this .table = new Entry[v];
275:                this .loadFactor = loadFactor;
276:                this .threshold = (int) (v * loadFactor);
277:            }
278:
279:            // used by constructor
280:            private static void verify(String name, int type) {
281:                if ((type < HARD) || (type > WEAK)) {
282:                    throw new IllegalArgumentException(name
283:                            + " must be HARD, SOFT, WEAK.");
284:                }
285:            }
286:
287:            /**
288:             *  Writes this object to the given output stream.
289:             *
290:             *  @param out  the output stream to write to
291:             *  @throws IOException  if the stream raises it
292:             */
293:            private void writeObject(ObjectOutputStream out) throws IOException {
294:                out.defaultWriteObject();
295:                out.writeInt(table.length);
296:
297:                // Have to use null-terminated list because size might shrink
298:                // during iteration
299:
300:                for (Iterator iter = entrySet().iterator(); iter.hasNext();) {
301:                    Map.Entry entry = (Map.Entry) iter.next();
302:                    out.writeObject(entry.getKey());
303:                    out.writeObject(entry.getValue());
304:                }
305:                out.writeObject(null);
306:            }
307:
308:            /**
309:             *  Reads the contents of this object from the given input stream.
310:             *
311:             *  @param inp  the input stream to read from
312:             *  @throws IOException  if the stream raises it
313:             *  @throws ClassNotFoundException  if the stream raises it
314:             */
315:            private void readObject(ObjectInputStream inp) throws IOException,
316:                    ClassNotFoundException {
317:                inp.defaultReadObject();
318:                table = new Entry[inp.readInt()];
319:                threshold = (int) (table.length * loadFactor);
320:                queue = new ReferenceQueue();
321:                Object key = inp.readObject();
322:                while (key != null) {
323:                    Object value = inp.readObject();
324:                    put(key, value);
325:                    key = inp.readObject();
326:                }
327:            }
328:
329:            /**
330:             *  Constructs a reference of the given type to the given 
331:             *  referent.  The reference is registered with the queue
332:             *  for later purging.
333:             *
334:             *  @param type  HARD, SOFT or WEAK
335:             *  @param referent  the object to refer to
336:             *  @param hash  the hash code of the <I>key</I> of the mapping;
337:             *    this number might be different from referent.hashCode() if
338:             *    the referent represents a value and not a key
339:             */
340:            private Object toReference(int type, Object referent, int hash) {
341:                switch (type) {
342:                case HARD:
343:                    return referent;
344:                case SOFT:
345:                    return new SoftRef(hash, referent, queue);
346:                case WEAK:
347:                    return new WeakRef(hash, referent, queue);
348:                default:
349:                    throw new Error();
350:                }
351:            }
352:
353:            /**
354:             *  Returns the entry associated with the given key.
355:             *
356:             *  @param key  the key of the entry to look up
357:             *  @return  the entry associated with that key, or null
358:             *    if the key is not in this map
359:             */
360:            private Entry getEntry(Object key) {
361:                if (key == null)
362:                    return null;
363:                int hash = key.hashCode();
364:                int index = indexFor(hash);
365:                for (Entry entry = table[index]; entry != null; entry = entry.next) {
366:                    if ((entry.hash == hash) && key.equals(entry.getKey())) {
367:                        return entry;
368:                    }
369:                }
370:                return null;
371:            }
372:
373:            /**
374:             *  Converts the given hash code into an index into the
375:             *  hash table.
376:             */
377:            private int indexFor(int hash) {
378:                // mix the bits to avoid bucket collisions...
379:                hash += ~(hash << 15);
380:                hash ^= (hash >>> 10);
381:                hash += (hash << 3);
382:                hash ^= (hash >>> 6);
383:                hash += ~(hash << 11);
384:                hash ^= (hash >>> 16);
385:                return hash & (table.length - 1);
386:            }
387:
388:            /**
389:             *  Resizes this hash table by doubling its capacity.
390:             *  This is an expensive operation, as entries must
391:             *  be copied from the old smaller table to the new 
392:             *  bigger table.
393:             */
394:            private void resize() {
395:                Entry[] old = table;
396:                table = new Entry[old.length * 2];
397:
398:                for (int i = 0; i < old.length; i++) {
399:                    Entry next = old[i];
400:                    while (next != null) {
401:                        Entry entry = next;
402:                        next = next.next;
403:                        int index = indexFor(entry.hash);
404:                        entry.next = table[index];
405:                        table[index] = entry;
406:                    }
407:                    old[i] = null;
408:                }
409:                threshold = (int) (table.length * loadFactor);
410:            }
411:
412:            /**
413:             * Purges stale mappings from this map.
414:             * <p>
415:             * Ordinarily, stale mappings are only removed during
416:             * a write operation, although this method is called for both
417:             * read and write operations to maintain a consistent state.
418:             * <p>
419:             * Note that this method is not synchronized!  Special
420:             * care must be taken if, for instance, you want stale
421:             * mappings to be removed on a periodic basis by some
422:             * background thread.
423:             */
424:            private void purge() {
425:                Reference ref = queue.poll();
426:                while (ref != null) {
427:                    purge(ref);
428:                    ref = queue.poll();
429:                }
430:            }
431:
432:            private void purge(Reference ref) {
433:                // The hashCode of the reference is the hashCode of the
434:                // mapping key, even if the reference refers to the 
435:                // mapping value...
436:                int hash = ref.hashCode();
437:                int index = indexFor(hash);
438:                Entry previous = null;
439:                Entry entry = table[index];
440:                while (entry != null) {
441:                    if (entry.purge(ref)) {
442:                        if (previous == null)
443:                            table[index] = entry.next;
444:                        else
445:                            previous.next = entry.next;
446:                        this .size--;
447:                        return;
448:                    }
449:                    previous = entry;
450:                    entry = entry.next;
451:                }
452:
453:            }
454:
455:            /**
456:             *  Returns the size of this map.
457:             *
458:             *  @return  the size of this map
459:             */
460:            public int size() {
461:                purge();
462:                return size;
463:            }
464:
465:            /**
466:             *  Returns <code>true</code> if this map is empty.
467:             *
468:             *  @return <code>true</code> if this map is empty
469:             */
470:            public boolean isEmpty() {
471:                purge();
472:                return size == 0;
473:            }
474:
475:            /**
476:             *  Returns <code>true</code> if this map contains the given key.
477:             *
478:             *  @return true if the given key is in this map
479:             */
480:            public boolean containsKey(Object key) {
481:                purge();
482:                Entry entry = getEntry(key);
483:                if (entry == null)
484:                    return false;
485:                return entry.getValue() != null;
486:            }
487:
488:            /**
489:             *  Returns the value associated with the given key, if any.
490:             *
491:             *  @return the value associated with the given key, or <code>null</code>
492:             *   if the key maps to no value
493:             */
494:            public Object get(Object key) {
495:                purge();
496:                Entry entry = getEntry(key);
497:                if (entry == null)
498:                    return null;
499:                return entry.getValue();
500:            }
501:
502:            /**
503:             *  Associates the given key with the given value.<p>
504:             *  Neither the key nor the value may be null.
505:             *
506:             *  @param key  the key of the mapping
507:             *  @param value  the value of the mapping
508:             *  @return  the last value associated with that key, or 
509:             *   null if no value was associated with the key
510:             *  @throws NullPointerException if either the key or value
511:             *   is null
512:             */
513:            public Object put(Object key, Object value) {
514:                if (key == null)
515:                    throw new NullPointerException("null keys not allowed");
516:                if (value == null)
517:                    throw new NullPointerException("null values not allowed");
518:
519:                purge();
520:                if (size + 1 > threshold)
521:                    resize();
522:
523:                int hash = key.hashCode();
524:                int index = indexFor(hash);
525:                Entry entry = table[index];
526:                while (entry != null) {
527:                    if ((hash == entry.hash) && key.equals(entry.getKey())) {
528:                        Object result = entry.getValue();
529:                        entry.setValue(value);
530:                        return result;
531:                    }
532:                    entry = entry.next;
533:                }
534:                this .size++;
535:                modCount++;
536:                key = toReference(keyType, key, hash);
537:                value = toReference(valueType, value, hash);
538:                table[index] = new Entry(key, hash, value, table[index]);
539:                return null;
540:            }
541:
542:            /**
543:             *  Removes the key and its associated value from this map.
544:             *
545:             *  @param key  the key to remove
546:             *  @return the value associated with that key, or null if
547:             *   the key was not in the map
548:             */
549:            public Object remove(Object key) {
550:                if (key == null)
551:                    return null;
552:                purge();
553:                int hash = key.hashCode();
554:                int index = indexFor(hash);
555:                Entry previous = null;
556:                Entry entry = table[index];
557:                while (entry != null) {
558:                    if ((hash == entry.hash) && key.equals(entry.getKey())) {
559:                        if (previous == null)
560:                            table[index] = entry.next;
561:                        else
562:                            previous.next = entry.next;
563:                        this .size--;
564:                        modCount++;
565:                        return entry.getValue();
566:                    }
567:                    previous = entry;
568:                    entry = entry.next;
569:                }
570:                return null;
571:            }
572:
573:            /**
574:             *  Clears this map.
575:             */
576:            public void clear() {
577:                Arrays.fill(table, null);
578:                size = 0;
579:                while (queue.poll() != null)
580:                    ; // drain the queue
581:            }
582:
583:            /**
584:             *  Returns a set view of this map's entries.
585:             *
586:             *  @return a set view of this map's entries
587:             */
588:            public Set entrySet() {
589:                if (entrySet != null) {
590:                    return entrySet;
591:                }
592:                entrySet = new AbstractSet() {
593:                    public int size() {
594:                        return ReferenceMap.this .size();
595:                    }
596:
597:                    public void clear() {
598:                        ReferenceMap.this .clear();
599:                    }
600:
601:                    public boolean contains(Object o) {
602:                        if (o == null)
603:                            return false;
604:                        if (!(o instanceof  Map.Entry))
605:                            return false;
606:                        Map.Entry e = (Map.Entry) o;
607:                        Entry e2 = getEntry(e.getKey());
608:                        return (e2 != null) && e.equals(e2);
609:                    }
610:
611:                    public boolean remove(Object o) {
612:                        boolean r = contains(o);
613:                        if (r) {
614:                            Map.Entry e = (Map.Entry) o;
615:                            ReferenceMap.this .remove(e.getKey());
616:                        }
617:                        return r;
618:                    }
619:
620:                    public Iterator iterator() {
621:                        return new EntryIterator();
622:                    }
623:
624:                    public Object[] toArray() {
625:                        return toArray(new Object[0]);
626:                    }
627:
628:                    public Object[] toArray(Object[] arr) {
629:                        ArrayList list = new ArrayList();
630:                        Iterator iterator = iterator();
631:                        while (iterator.hasNext()) {
632:                            Entry e = (Entry) iterator.next();
633:                            list.add(new DefaultMapEntry(e.getKey(), e
634:                                    .getValue()));
635:                        }
636:                        return list.toArray(arr);
637:                    }
638:                };
639:                return entrySet;
640:            }
641:
642:            /**
643:             *  Returns a set view of this map's keys.
644:             *
645:             *  @return a set view of this map's keys
646:             */
647:            public Set keySet() {
648:                if (keySet != null)
649:                    return keySet;
650:                keySet = new AbstractSet() {
651:                    public int size() {
652:                        return ReferenceMap.this .size();
653:                    }
654:
655:                    public Iterator iterator() {
656:                        return new KeyIterator();
657:                    }
658:
659:                    public boolean contains(Object o) {
660:                        return containsKey(o);
661:                    }
662:
663:                    public boolean remove(Object o) {
664:                        Object r = ReferenceMap.this .remove(o);
665:                        return r != null;
666:                    }
667:
668:                    public void clear() {
669:                        ReferenceMap.this .clear();
670:                    }
671:
672:                    public Object[] toArray() {
673:                        return toArray(new Object[0]);
674:                    }
675:
676:                    public Object[] toArray(Object[] array) {
677:                        Collection c = new ArrayList(size());
678:                        for (Iterator it = iterator(); it.hasNext();) {
679:                            c.add(it.next());
680:                        }
681:                        return c.toArray(array);
682:                    }
683:                };
684:                return keySet;
685:            }
686:
687:            /**
688:             *  Returns a collection view of this map's values.
689:             *
690:             *  @return a collection view of this map's values.
691:             */
692:            public Collection values() {
693:                if (values != null)
694:                    return values;
695:                values = new AbstractCollection() {
696:                    public int size() {
697:                        return ReferenceMap.this .size();
698:                    }
699:
700:                    public void clear() {
701:                        ReferenceMap.this .clear();
702:                    }
703:
704:                    public Iterator iterator() {
705:                        return new ValueIterator();
706:                    }
707:
708:                    public Object[] toArray() {
709:                        return toArray(new Object[0]);
710:                    }
711:
712:                    public Object[] toArray(Object[] array) {
713:                        Collection c = new ArrayList(size());
714:                        for (Iterator it = iterator(); it.hasNext();) {
715:                            c.add(it.next());
716:                        }
717:                        return c.toArray(array);
718:                    }
719:                };
720:                return values;
721:            }
722:
723:            // If getKey() or getValue() returns null, it means
724:            // the mapping is stale and should be removed.
725:            private class Entry implements  Map.Entry, KeyValue {
726:
727:                Object key;
728:                Object value;
729:                int hash;
730:                Entry next;
731:
732:                public Entry(Object key, int hash, Object value, Entry next) {
733:                    this .key = key;
734:                    this .hash = hash;
735:                    this .value = value;
736:                    this .next = next;
737:                }
738:
739:                public Object getKey() {
740:                    return (keyType > HARD) ? ((Reference) key).get() : key;
741:                }
742:
743:                public Object getValue() {
744:                    return (valueType > HARD) ? ((Reference) value).get()
745:                            : value;
746:                }
747:
748:                public Object setValue(Object object) {
749:                    Object old = getValue();
750:                    if (valueType > HARD)
751:                        ((Reference) value).clear();
752:                    value = toReference(valueType, object, hash);
753:                    return old;
754:                }
755:
756:                public boolean equals(Object o) {
757:                    if (o == null)
758:                        return false;
759:                    if (o == this )
760:                        return true;
761:                    if (!(o instanceof  Map.Entry))
762:                        return false;
763:
764:                    Map.Entry entry = (Map.Entry) o;
765:                    Object key = entry.getKey();
766:                    Object value = entry.getValue();
767:                    if ((key == null) || (value == null))
768:                        return false;
769:                    return key.equals(getKey()) && value.equals(getValue());
770:                }
771:
772:                public int hashCode() {
773:                    Object v = getValue();
774:                    return hash ^ ((v == null) ? 0 : v.hashCode());
775:                }
776:
777:                public String toString() {
778:                    return getKey() + "=" + getValue();
779:                }
780:
781:                boolean purge(Reference ref) {
782:                    boolean r = (keyType > HARD) && (key == ref);
783:                    r = r || ((valueType > HARD) && (value == ref));
784:                    if (r) {
785:                        if (keyType > HARD)
786:                            ((Reference) key).clear();
787:                        if (valueType > HARD) {
788:                            ((Reference) value).clear();
789:                        } else if (purgeValues) {
790:                            value = null;
791:                        }
792:                    }
793:                    return r;
794:                }
795:            }
796:
797:            private class EntryIterator implements  Iterator {
798:                // These fields keep track of where we are in the table.
799:                int index;
800:                Entry entry;
801:                Entry previous;
802:
803:                // These Object fields provide hard references to the
804:                // current and next entry; this assures that if hasNext()
805:                // returns true, next() will actually return a valid element.
806:                Object nextKey, nextValue;
807:                Object currentKey, currentValue;
808:
809:                int expectedModCount;
810:
811:                public EntryIterator() {
812:                    index = (size() != 0 ? table.length : 0);
813:                    // have to do this here!  size() invocation above
814:                    // may have altered the modCount.
815:                    expectedModCount = modCount;
816:                }
817:
818:                public boolean hasNext() {
819:                    checkMod();
820:                    while (nextNull()) {
821:                        Entry e = entry;
822:                        int i = index;
823:                        while ((e == null) && (i > 0)) {
824:                            i--;
825:                            e = table[i];
826:                        }
827:                        entry = e;
828:                        index = i;
829:                        if (e == null) {
830:                            currentKey = null;
831:                            currentValue = null;
832:                            return false;
833:                        }
834:                        nextKey = e.getKey();
835:                        nextValue = e.getValue();
836:                        if (nextNull())
837:                            entry = entry.next;
838:                    }
839:                    return true;
840:                }
841:
842:                private void checkMod() {
843:                    if (modCount != expectedModCount) {
844:                        throw new ConcurrentModificationException();
845:                    }
846:                }
847:
848:                private boolean nextNull() {
849:                    return (nextKey == null) || (nextValue == null);
850:                }
851:
852:                protected Entry nextEntry() {
853:                    checkMod();
854:                    if (nextNull() && !hasNext())
855:                        throw new NoSuchElementException();
856:                    previous = entry;
857:                    entry = entry.next;
858:                    currentKey = nextKey;
859:                    currentValue = nextValue;
860:                    nextKey = null;
861:                    nextValue = null;
862:                    return previous;
863:                }
864:
865:                public Object next() {
866:                    return nextEntry();
867:                }
868:
869:                public void remove() {
870:                    checkMod();
871:                    if (previous == null)
872:                        throw new IllegalStateException();
873:                    ReferenceMap.this .remove(currentKey);
874:                    previous = null;
875:                    currentKey = null;
876:                    currentValue = null;
877:                    expectedModCount = modCount;
878:                }
879:
880:            }
881:
882:            private class ValueIterator extends EntryIterator {
883:                public Object next() {
884:                    return nextEntry().getValue();
885:                }
886:            }
887:
888:            private class KeyIterator extends EntryIterator {
889:                public Object next() {
890:                    return nextEntry().getKey();
891:                }
892:            }
893:
894:            // These two classes store the hashCode of the key of
895:            // of the mapping, so that after they're dequeued a quick
896:            // lookup of the bucket in the table can occur.
897:
898:            private static class SoftRef extends SoftReference {
899:                private int hash;
900:
901:                public SoftRef(int hash, Object r, ReferenceQueue q) {
902:                    super (r, q);
903:                    this .hash = hash;
904:                }
905:
906:                public int hashCode() {
907:                    return hash;
908:                }
909:            }
910:
911:            private static class WeakRef extends WeakReference {
912:                private int hash;
913:
914:                public WeakRef(int hash, Object r, ReferenceQueue q) {
915:                    super (r, q);
916:                    this .hash = hash;
917:                }
918:
919:                public int hashCode() {
920:                    return hash;
921:                }
922:            }
923:
924:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.