Weak Value HashMap : WeakHashMap « Collections Data Structure « Java

Java
1. 2D Graphics GUI
2. 3D
3. Advanced Graphics
4. Ant
5. Apache Common
6. Chart
7. Class
8. Collections Data Structure
9. Data Type
10. Database SQL JDBC
11. Design Pattern
12. Development Class
13. EJB3
14. Email
15. Event
16. File Input Output
17. Game
18. Generics
19. GWT
20. Hibernate
21. I18N
22. J2EE
23. J2ME
24. JDK 6
25. JNDI LDAP
26. JPA
27. JSP
28. JSTL
29. Language Basics
30. Network Protocol
31. PDF RTF
32. Reflection
33. Regular Expressions
34. Scripting
35. Security
36. Servlets
37. Spring
38. Swing Components
39. Swing JFC
40. SWT JFace Eclipse
41. Threads
42. Tiny Application
43. Velocity
44. Web Services SOA
45. XML
Java Tutorial
Java Source Code / Java Documentation
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 » Collections Data Structure » WeakHashMapScreenshots 
Weak Value HashMap
  
/*
 * The contents of this file are subject to the terms 
 * of the Common Development and Distribution License 
 * (the "License").  You may not use this file except 
 * in compliance with the License.
 
 * You can obtain a copy of the license at 
 * glassfish/bootstrap/legal/CDDLv1.0.txt or 
 * https://glassfish.dev.java.net/public/CDDLv1.0.html. 
 * See the License for the specific language governing 
 * permissions and limitations under the License.
 
 * When distributing Covered Code, include this CDDL 
 * HEADER in each file and include the License file at 
 * glassfish/bootstrap/legal/CDDLv1.0.txt.  If applicable, 
 * add the following below this CDDL HEADER, with the 
 * fields enclosed by brackets "[]" replaced with your 
 * own identifying information: Portions Copyright [yyyy] 
 * [name of copyright owner]
 */

/*
 * Copyright 2005 The Apache Software Foundation.
 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at 
 
 *     http://www.apache.org/licenses/LICENSE-2.0
 
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License.
 */


import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;

import java.util.AbstractCollection;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;

/**
 * A WeakValueHashMap is implemented as a HashMap that maps keys to
 * WeakValues.  Because we don't have access to the innards of the
 * HashMap, we have to wrap/unwrap value objects with WeakValues on
 * every operation.  Fortunately WeakValues are small, short-lived
 * objects, so the added allocation overhead is tolerable. This
 * implementaton directly extends java.util.HashMap.
 *
 @author  Markus Fuchs
 @see   java.util.HashMap
 @see         java.lang.ref.WeakReference
 */

public class WeakValueHashMap extends HashMap {

    /* Reference queue for cleared WeakValues */
    private ReferenceQueue queue = new ReferenceQueue();

    /**
     * Returns the number of key-value mappings in this map.<p>
     @return the number of key-value mappings in this map.
     */
    public int size() {
        // delegate to entrySet, as super.size() also counts WeakValues
        return entrySet().size();
    }

    /**
     * Returns <tt>true</tt> if this map contains no key-value mappings.<p>
     @return <tt>true</tt> if this map contains no key-value mappings.
     */
    public boolean isEmpty() {
        return size() == 0;
    }

    /**
     * Returns <tt>true</tt> if this map contains a mapping for the specified
     * key.<p>
     @param key key whose presence in this map is to be tested
     @return <tt>true</tt> if this map contains a mapping for the specified
     * key.
     */
    public boolean containsKey(Object key) {
        // need to clean up gc'ed values before invoking super method
        processQueue();
        return super.containsKey(key);
    }

   /**
     * Returns <tt>true</tt> if this map maps one or more keys to the
     * specified value.<p>
     @param value value whose presence in this map is to be tested
     @return <tt>true</tt> if this map maps one or more keys to this value.
     */
    public boolean containsValue(Object value) {
        return super.containsValue(WeakValue.create(value));
    }

    /**
     * Gets the value for the given key.<p>
     @param key key whose associated value, if any, is to be returned
     @return the value to which this map maps the specified key.
     */
    public Object get(Object key) {
        // We don't need to remove garbage collected values here;
        // if they are garbage collected, the get() method returns null;
        // the next put() call with the same key removes the old value
        // automatically so that it can be completely garbage collected
        return getReferenceObject((WeakReferencesuper.get(key));
    }

    /**
     * Puts a new (key,value) into the map.<p>
     @param key key with which the specified value is to be associated.
     @param value value to be associated with the specified key.
     @return previous value associated with specified key, or null
     * if there was no mapping for key or the value has been garbage
     * collected by the garbage collector.
     */
    public Object put(Object key, Object value) {
        // If the map already contains an equivalent key, the new key
        // of a (key, value) pair is NOT stored in the map but the new
        // value only. But as the key is strongly referenced by the
        // map, it can not be removed from the garbage collector, even
        // if the key becomes weakly reachable due to the old
        // value. So, it isn't necessary to remove all garbage
        // collected values with their keys from the map before the
        // new entry is made. We only clean up here to distribute
        // clean up calls on different operations.
        processQueue();

        WeakValue oldValue = 
            (WeakValue)super.put(key, WeakValue.create(key, value, queue));
        return getReferenceObject(oldValue);
    }

    /**
     * Removes key and value for the given key.<p>
     @param key key whose mapping is to be removed from the map.
     @return previous value associated with specified key, or null
     * if there was no mapping for key or the value has been garbage
     * collected by the garbage collector.
     */
    public Object remove(Object key) {
        return getReferenceObject((WeakReferencesuper.remove(key));
    }

    /**
     * A convenience method to return the object held by the
     * weak reference or <code>null</code> if it does not exist.
     */
    private final Object getReferenceObject(WeakReference ref) {
        return (ref == nullnull : ref.get();
    }

    /**
     * Removes all garbage collected values with their keys from the map.
     * Since we don't know how much the ReferenceQueue.poll() operation
     * costs, we should not call it every map operation.
     */
    private void processQueue() {
        WeakValue wv = null;

        while ((wv = (WeakValuethis.queue.poll()) != null) {
            // "super" is not really necessary but use it
            // to be on the safe side
            super.remove(wv.key);
        }
    }

    /* -- Helper classes -- */

    /**
     * We need this special class to keep the backward reference from
     * the value to the key, so that we are able to remove the key if
     * the value is garbage collected.
     */
    private static class WeakValue extends WeakReference {
        /**
         * It's the same as the key in the map. We need the key to remove
         * the value if it is garbage collected.
         */
        private Object key;

        private WeakValue(Object value) {
            super(value);
        }

        /**
         * Creates a new weak reference without adding it to a
         * ReferenceQueue.
         */
  private static WeakValue create(Object value) {
      if (value == nullreturn null;
      else return new WeakValue(value);
        }

        private WeakValue(Object key, Object value, ReferenceQueue queue) {
            super(value, queue);
            this.key = key;
        }

        /**
         * Creates a new weak reference and adds it to the given queue.
         */
        private static WeakValue create(Object key, Object value, 
                                        ReferenceQueue queue) {
      if (value == nullreturn null;
      else return new WeakValue(key, value, queue);
        }

        /**
         * A WeakValue is equal to another WeakValue iff they both refer
         * to objects that are, in turn, equal according to their own
         * equals methods.
         */
        public boolean equals(Object obj) {
            if (this == obj)
                return true;

            if (!(obj instanceof WeakValue))
                return false;

            Object ref1 = this.get();
            Object ref2 = ((WeakValueobj).get();

            if (ref1 == ref2)
                return true;

            if ((ref1 == null|| (ref2 == null))
                return false;

            return ref1.equals(ref2);
        }

        /**
         *
         */
        public int hashCode() {
            Object ref = this.get();

            return (ref == null: ref.hashCode();
        }
    }

    /** 
     * Internal class for entries. This class wraps/unwraps the
     * values of the Entry objects returned from the underlying map.
     */
    private class Entry implements Map.Entry {
        private Map.Entry ent;
        private Object value; /* Strong reference to value, so that the
           GC will leave it alone as long as this
           Entry exists */

        Entry(Map.Entry ent, Object value) {
            this.ent = ent;
            this.value = value;
        }

        public Object getKey() {
            return ent.getKey();
        }

        public Object getValue() {
            return value;
        }

        public Object setValue(Object value) {
            // This call changes the map. Please see the comment on 
            // the put method for the correctness remark.
            Object oldValue = this.value;
            this.value = value;
            ent.setValue(WeakValue.create(getKey(), value, queue));
            return oldValue;
        }

        private boolean valEquals(Object o1, Object o2) {
            return (o1 == null(o2 == null: o1.equals(o2);
        }

        public boolean equals(Object o) {
            if (!(instanceof Map.Entry)) return false;
            Map.Entry e = (Map.Entryo;
            return (valEquals(ent.getKey(), e.getKey())
                    && valEquals(value, e.getValue()));
        }

        public int hashCode() {
            Object k;
            return ((((k = ent.getKey()) == null: k.hashCode())
                    ((value == null: value.hashCode()));
        }

    }

    /**
     * Internal class for entry sets to unwrap/wrap WeakValues stored
     * in the map.
     */
    private class EntrySet extends AbstractSet {

        public Iterator iterator() {
            // remove garbage collected elements
            processQueue();

            return new Iterator() {
                Iterator hashIterator = hashEntrySet.iterator();
                Entry next = null;

                public boolean hasNext() {
                    if (hashIterator.hasNext()) {
                        // since we removed garbage collected elements,
                        // we can simply return the next entry.
                        Map.Entry ent = (Map.EntryhashIterator.next();
                        WeakValue wv = (WeakValueent.getValue();
                        Object v = (wv == nullnull : wv.get();
                        next = new Entry(ent, v);
                        return true;
                    }
                    return false;
                }

                public Object next() {
                    if ((next == null&& !hasNext())
                        throw new NoSuchElementException();
                    Entry e = next;
                    next = null;
                    return e;
                }

                public void remove() {
                    hashIterator.remove();
                }

            };
        }

        public boolean isEmpty() {
            return !(iterator().hasNext());
        }

        public int size() {
            int j = 0;
            for (Iterator i = iterator(); i.hasNext(); i.next()) j++;
            return j;
        }

        public boolean remove(Object o) {
            if (!(instanceof Map.Entry)) return false;
            Map.Entry e = (Map.Entryo;
            Object ek = e.getKey();
            Object ev = e.getValue();
            Object hv = WeakValueHashMap.this.get(ek);
            if (hv == null) {
                // if the map's value is null, we have to check, if the
                // entry's value is null and the map contains the key
                if ((ev == null&& WeakValueHashMap.this.containsKey(ek)) {
                    WeakValueHashMap.this.remove(ek);
                    return true;
                else {
                    return false;
                }
                // otherwise, simply compare the values
            else if (hv.equals(ev)) {
                WeakValueHashMap.this.remove(ek);
                return true;
            }                
                
            return false;
        }

        public int hashCode() {
            int h = 0;
            for (Iterator i = hashEntrySet.iterator(); i.hasNext()) {
                Map.Entry ent = (Map.Entryi.next();
                Object k;
                WeakValue wv = (WeakValueent.getValue();
                if (wv == nullcontinue;
                h += ((((k = ent.getKey()) == null: k.hashCode())
                        ^ wv.hashCode());
            }
            return h;
        }

    }

    // internal helper variable, because we can't access
    // entrySet from the superclass inside the EntrySet class
    private Set hashEntrySet = null;
    // stores the EntrySet instance
    private Set entrySet = null;

    /**
     * Returns a <code>Set</code> view of the mappings in this map.<p>
     @return a <code>Set</code> view of the mappings in this map.
     */
    public Set entrySet() {
        if (entrySet == null) {
            hashEntrySet = super.entrySet();
            entrySet = new EntrySet();
        }
        return entrySet;
    }

    // stores the value collection
    private transient Collection values = null;

    /**
     * Returns a <code>Collection</code> view of the values contained
     * in this map.<p>
     @return a <code>Collection</code> view of the values contained
     * in this map.
     */
    public Collection values() {
        // delegates to entrySet, because super method returns
        // WeakValues instead of value objects
  if (values == null) {
      values = new AbstractCollection() {
    public Iterator iterator() {
        return new Iterator() {
      private Iterator i = entrySet().iterator();

      public boolean hasNext() {
          return i.hasNext();
      }

      public Object next() {
          return ((Entry)i.next()).getValue();
      }

      public void remove() {
          i.remove();
      }
                    };
                }

    public int size() {
        return WeakValueHashMap.this.size();
    }

    public boolean contains(Object v) {
        return WeakValueHashMap.this.containsValue(v);
    }
      };
  }
  return values;
    }

}

   
    
  
Related examples in the same category
1. To enable automatically release of the value, the value must be wrapped in a WeakReference object
2. Create a WeakHashMap with a single element in it
3. A WeakValueHashMap is implemented as a HashMap that maps keys to Weak Values
4. Implements a combination of WeakHashMap and IdentityHashMap
5. Weak ValueMap
6. Weak Valued HashMap
7. Weak Identity Map
8. A hashtable-based Map implementation with weak keys and using reference-equality in place of object-equality when comparing keys (and values).
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.