Weak ValueMap : WeakHashMap « Collections Data Structure « Java






Weak ValueMap

    
/*
 * Copyright 2002-2006 (C) TJDO.
 * All rights reserved.
 *
 * This software is distributed under the terms of the TJDO License version 1.0.
 * See the terms of the TJDO License in the documentation provided with this software.
 *
 * $Id: WeakValueMap.java,v 1.5 2006/09/08 16:11:28 jackknifebarber Exp $
 */


import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;


/**
 * A <code>java.util.Map</code> implementation with weak values.
 * <p>
 * The values are stored in the map as weak references.
 * If the garbage collector clears the reference, the corresponding key is
 * automatically removed from the map.
 *
 * @author <a href="mailto:mmartin5@austin.rr.com">Mike Martin</a>
 * @version $Revision: 1.5 $
 *
 * @see WeakReference
 */

public class WeakValueMap extends ReferenceValueMap
{
    public WeakValueMap()
    {
        super(new HashMap());
    }

    public WeakValueMap(int initialCapacity)
    {
        super(new HashMap(initialCapacity));
    }

    public WeakValueMap(int initialCapacity, float loadFactor)
    {
        super(new HashMap(initialCapacity, loadFactor));
    }

    public WeakValueMap(Map m)
    {
        super(new HashMap(m));
    }

    protected Reference newReference(Object value)
    {
        return new WeakReference(value, refQueue);
    }
}


/**
 * A <code>java.util.Map</code> implementation using reference values.
 * <p>
 * The values are stored in the map as references.
 * If the garbage collector clears the reference, the corresponding key is
 * automatically removed from the map.
 *
 * @author  <a href="mailto:jackknifebarber@users.sourceforge.net">Mike Martin</a>
 * @version $Revision: 1.8 $
 */

abstract class ReferenceValueMap extends AbstractMap
{
    protected final ReferenceQueue refQueue = new ReferenceQueue();
    /** Backing map. */
    private final Map backing;

    ReferenceValueMap(Map backing)
    {
        this.backing = backing;
    }

    /**
     * Returns a new <code>Reference</code> object to be inserted into the map.
     * Subclasses must implement this method to construct <code>Reference</code>
     * objects of the desired type (e.g. <code>SoftReference</code>, etc.).
     *
     * @param value
     *      The associated value to be referenced.
     *
     * @return
     *      A new <code>Reference</code> object to be inserted into the map.
     */
    protected abstract Reference newReference(Object value);

    private void reap()
    {
        Reference ref;

        while ((ref = refQueue.poll()) != null)
            backing.values().remove(ref);
    }

    public Object put(Object key, Object value)
    {
        reap();
        return backing.put(key, newReference(value));
    }

    public Object get(Object key)
    {
        reap();

        Object v = backing.get(key);

        return (v instanceof Reference) ? ((Reference)v).get() : v;
    }

    public int size()
    {
        reap();
        return backing.size();
    }

    public boolean isEmpty()
    {
        reap();
        return backing.isEmpty();
    }

    public boolean containsKey(Object key)
    {
        reap();
        return backing.containsKey(key);
    }

    public boolean containsValue(Object value)
    {
        reap();
        return super.containsValue(value);
    }

    public Set keySet()
    {
        reap();
        return backing.keySet();
    }

    public Collection values()
    {
        reap();
        return super.values();
    }

    public Set entrySet()
    {
        reap();
        return new EntrySet();
    }

    public Object remove(Object key)
    {
        reap();
        return backing.remove(key);
    }

    public int hashCode()
    {
        reap();
        return super.hashCode();
    }

    public boolean equals(Object o)
    {
        reap();
        return super.equals(o);
    }

    public String toString()
    {
        reap();
        return super.toString();
    }

    static boolean eq(Object o1, Object o2)
    {
        return o1 == null ? o2 == null : o1.equals(o2);
    }

    private class EntrySet extends AbstractSet
    {
        /** Backing set. */
        private final Set set = backing.entrySet();

        public Iterator iterator()
        {
            return new Iterator()
            {
                private Iterator i = set.iterator();

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

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

                public Object next()
                {
                    final Map.Entry ent = (Map.Entry)i.next();

                    return new Map.Entry()
                    {
                        public Object getKey()
                        {
                            return ent.getKey();
                        }

                        public Object getValue()
                        {
                            Object v = ent.getValue();

                            return (v instanceof Reference) ? ((Reference)v).get() : v;
                        }

                        public Object setValue(Object v)
                        {
                            Object oldVal = getValue();
                            ent.setValue(newReference(v));
                            return oldVal;
                        }

                        public boolean equals(Object o)
                        {
                            if (o == this)
                                return true;
                            if (!(o instanceof Map.Entry))
                                return false;

                            Map.Entry e = (Map.Entry)o;
                            return eq(ent.getKey(), e.getKey())
                                && eq(ent.getValue(), e.getValue());
                        }

                        public int hashCode()
                        {
                            Object key = ent.getKey();
                            Object val = ent.getValue();

                            return (key == null ? 0 : key.hashCode())
                                 ^ (val == null ? 0 : val.hashCode());
                        }

                        public String toString()
                        {
                            return ent.getKey() + "=" + ent.getValue();
                        }
                    };
                }
            };
        }

        public int size()
        {
            reap();
            return set.size();
        }

        public boolean isEmpty()
        {
            reap();
            return set.isEmpty();
        }

        public boolean contains(Object o)
        {
            reap();
            return super.contains(o);
        }

        public Object[] toArray()
        {
            reap();
            return super.toArray();
        }

        public Object[] toArray(Object[] a)
        {
            reap();
            return super.toArray(a);
        }

        public boolean remove(Object o)
        {
            reap();
            return super.remove(o);
        }

        public boolean containsAll(Collection c)
        {
            reap();
            return super.containsAll(c);
        }

        public boolean removeAll(Collection c)
        {
            reap();
            return super.removeAll(c);
        }

        public boolean retainAll(Collection c)
        {
            reap();
            return super.retainAll(c);
        }

        public void clear()
        {
            set.clear();
        }

        public String toString()
        {
            reap();
            return super.toString();
        }
    }
}

   
    
    
    
  








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 Valued HashMap
6.Weak Value 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).
9.A hash table with weak keys, full concurrency of retrievals, and adjustable expected concurrency for updates.
10.Map which stores items using SoftReference.