Source Code Cross Referenced for ReferenceMap.java in  » Library » Apache-commons-beanutils-1.8.0-BETA-src » 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 commons beanutils 1.8.0 BETA src » org.apache.commons.collections 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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