FileDocCategorySizeDatePackage
WeakHashMap.javaAPI DocAndroid 1.5 API22413Wed May 06 22:41:04 BST 2009java.util

WeakHashMap

public class WeakHashMap extends AbstractMap implements Map
WeakHashMap is an implementation of Map with keys which are WeakReferences. A key/value mapping is removed when the key is no longer referenced. All optional operations (adding and removing) are supported. Keys and values can be any objects. Note that the garbage collector acts similar to a second thread on this collection, possibly removing keys.
see
HashMap
see
WeakReference
since
Android 1.0

Fields Summary
private static final int
DEFAULT_SIZE
private final ReferenceQueue
referenceQueue
int
elementCount
Entry[]
elementData
private final int
loadFactor
private int
threshold
volatile int
modCount
Constructors Summary
public WeakHashMap()
Constructs a new empty {@code WeakHashMap} instance.

since
Android 1.0

        this(DEFAULT_SIZE);
    
public WeakHashMap(int capacity)
Constructs a new {@code WeakHashMap} instance with the specified capacity.

param
capacity the initial capacity of this map.
throws
IllegalArgumentException if the capacity is less than zero.
since
Android 1.0

        if (capacity >= 0) {
            elementCount = 0;
            elementData = newEntryArray(capacity == 0 ? 1 : capacity);
            loadFactor = 7500; // Default load factor of 0.75
            computeMaxSize();
            referenceQueue = new ReferenceQueue<K>();
        } else {
            throw new IllegalArgumentException();
        }
    
public WeakHashMap(int capacity, float loadFactor)
Constructs a new {@code WeakHashMap} instance with the specified capacity and load factor.

param
capacity the initial capacity of this map.
param
loadFactor the initial load factor.
throws
IllegalArgumentException if the capacity is less than zero or the load factor is less or equal to zero.
since
Android 1.0

        if (capacity >= 0 && loadFactor > 0) {
            elementCount = 0;
            elementData = newEntryArray(capacity == 0 ? 1 : capacity);
            this.loadFactor = (int) (loadFactor * 10000);
            computeMaxSize();
            referenceQueue = new ReferenceQueue<K>();
        } else {
            throw new IllegalArgumentException();
        }
    
public WeakHashMap(Map map)
Constructs a new {@code WeakHashMap} instance containing the mappings from the specified map.

param
map the mappings to add.
since
Android 1.0

        this(map.size() < 6 ? 11 : map.size() * 2);
        putAllImpl(map);
    
Methods Summary
public voidclear()
Removes all mappings from this map, leaving it empty.

see
#isEmpty()
see
#size()
since
Android 1.0

        if (elementCount > 0) {
            elementCount = 0;
            Arrays.fill(elementData, null);
            modCount++;
            while (referenceQueue.poll() != null) {
                // do nothing
            }
        }
    
private voidcomputeMaxSize()

        threshold = (int) ((long) elementData.length * loadFactor / 10000);
    
public booleancontainsKey(java.lang.Object key)
Returns whether this map contains the specified key.

param
key the key to search for.
return
{@code true} if this map contains the specified key, {@code false} otherwise.
since
Android 1.0

        return getEntry(key) != null;
    
public booleancontainsValue(java.lang.Object value)
Returns whether this map contains the specified value.

param
value the value to search for.
return
{@code true} if this map contains the specified value, {@code false} otherwise.
since
Android 1.0

        poll();
        if (value != null) {
            for (int i = elementData.length; --i >= 0;) {
                Entry<K, V> entry = elementData[i];
                while (entry != null) {
                    K key = entry.get();
                    if ((key != null || entry.isNull)
                            && value.equals(entry.value)) {
                        return true;
                    }
                    entry = entry.next;
                }
            }
        } else {
            for (int i = elementData.length; --i >= 0;) {
                Entry<K, V> entry = elementData[i];
                while (entry != null) {
                    K key = entry.get();
                    if ((key != null || entry.isNull) && entry.value == null) {
                        return true;
                    }
                    entry = entry.next;
                }
            }
        }
        return false;
    
public java.util.SetentrySet()
Returns a set containing all of the mappings in this map. Each mapping is an instance of {@link Map.Entry}. As the set is backed by this map, changes in one will be reflected in the other. It does not support adding operations.

return
a set of the mappings.
since
Android 1.0

        poll();
        return new AbstractSet<Map.Entry<K, V>>() {
            @Override
            public int size() {
                return WeakHashMap.this.size();
            }

            @Override
            public void clear() {
                WeakHashMap.this.clear();
            }

            @Override
            public boolean remove(Object object) {
                if (contains(object)) {
                    WeakHashMap.this
                            .remove(((Map.Entry<?, ?>) object).getKey());
                    return true;
                }
                return false;
            }

            @Override
            public boolean contains(Object object) {
                if (object instanceof Map.Entry) {
                    Entry<?, ?> entry = getEntry(((Map.Entry<?, ?>) object)
                            .getKey());
                    if (entry != null) {
                        Object key = entry.get();
                        if (key != null || entry.isNull) {
                            return object.equals(entry);
                        }
                    }
                }
                return false;
            }

            @Override
            public Iterator<Map.Entry<K, V>> iterator() {
                return new HashIterator<Map.Entry<K, V>>(
                        new Entry.Type<Map.Entry<K, V>, K, V>() {
                            public Map.Entry<K, V> get(Map.Entry<K, V> entry) {
                                return entry;
                            }
                        });
            }
        };
    
public Vget(java.lang.Object key)
Returns the value of the mapping with the specified key.

param
key the key.
return
the value of the mapping with the specified key, or {@code null} if no mapping for the specified key is found.
since
Android 1.0

        poll();
        if (key != null) {
            int index = (key.hashCode() & 0x7FFFFFFF) % elementData.length;
            Entry<K, V> entry = elementData[index];
            while (entry != null) {
                if (key.equals(entry.get())) {
                    return entry.value;
                }
                entry = entry.next;
            }
            return null;
        }
        Entry<K, V> entry = elementData[0];
        while (entry != null) {
            if (entry.isNull) {
                return entry.value;
            }
            entry = entry.next;
        }
        return null;
    
java.util.WeakHashMap$EntrygetEntry(java.lang.Object key)

        poll();
        if (key != null) {
            int index = (key.hashCode() & 0x7FFFFFFF) % elementData.length;
            Entry<K, V> entry = elementData[index];
            while (entry != null) {
                if (key.equals(entry.get())) {
                    return entry;
                }
                entry = entry.next;
            }
            return null;
        }
        Entry<K, V> entry = elementData[0];
        while (entry != null) {
            if (entry.isNull) {
                return entry;
            }
            entry = entry.next;
        }
        return null;
    
public booleanisEmpty()
Returns the number of elements in this map.

return
the number of elements in this map.
since
Android 1.0

        return size() == 0;
    
public java.util.SetkeySet()
Returns a set of the keys contained in this map. The set is backed by this map so changes to one are reflected by the other. The set does not support adding.

return
a set of the keys.
since
Android 1.0

        poll();
        if (keySet == null) {
            keySet = new AbstractSet<K>() {
                @Override
                public boolean contains(Object object) {
                    return containsKey(object);
                }

                @Override
                public int size() {
                    return WeakHashMap.this.size();
                }

                @Override
                public void clear() {
                    WeakHashMap.this.clear();
                }

                @Override
                public boolean remove(Object key) {
                    if (containsKey(key)) {
                        WeakHashMap.this.remove(key);
                        return true;
                    }
                    return false;
                }

                @Override
                public Iterator<K> iterator() {
                    return new HashIterator<K>(new Entry.Type<K, K, V>() {
                        public K get(Map.Entry<K, V> entry) {
                            return entry.getKey();
                        }
                    });
                }
            };
        }
        return keySet;
    
private static java.util.WeakHashMap$Entry[]newEntryArray(int size)

        return new Entry[size];
    
voidpoll()

        Entry<K, V> toRemove;
        while ((toRemove = (Entry<K, V>) referenceQueue.poll()) != null) {
            removeEntry(toRemove);
        }
    
public Vput(K key, V value)
Maps the specified key to the specified value.

param
key the key.
param
value the value.
return
the value of any previous mapping with the specified key or {@code null} if there was no mapping.
since
Android 1.0

        poll();
        int index = 0;
        Entry<K, V> entry;
        if (key != null) {
            index = (key.hashCode() & 0x7FFFFFFF) % elementData.length;
            entry = elementData[index];
            while (entry != null && !key.equals(entry.get())) {
                entry = entry.next;
            }
        } else {
            entry = elementData[0];
            while (entry != null && !entry.isNull) {
                entry = entry.next;
            }
        }
        if (entry == null) {
            modCount++;
            if (++elementCount > threshold) {
                rehash();
                index = key == null ? 0 : (key.hashCode() & 0x7FFFFFFF)
                        % elementData.length;
            }
            entry = new Entry<K, V>(key, value, referenceQueue);
            entry.next = elementData[index];
            elementData[index] = entry;
            return null;
        }
        V result = entry.value;
        entry.value = value;
        return result;
    
public voidputAll(java.util.Map map)
Copies all the mappings in the given map to this map. These mappings will replace all mappings that this map had for any of the keys currently in the given map.

param
map the map to copy mappings from.
since
Android 1.0

        putAllImpl(map);
    
private voidputAllImpl(java.util.Map map)

        if (map.entrySet() != null) {
            super.putAll(map);
        }
    
private voidrehash()

        int length = elementData.length << 1;
        if (length == 0) {
            length = 1;
        }
        Entry<K, V>[] newData = newEntryArray(length);
        for (int i = 0; i < elementData.length; i++) {
            Entry<K, V> entry = elementData[i];
            while (entry != null) {
                int index = entry.isNull ? 0 : (entry.hash & 0x7FFFFFFF)
                        % length;
                Entry<K, V> next = entry.next;
                entry.next = newData[index];
                newData[index] = entry;
                entry = next;
            }
        }
        elementData = newData;
        computeMaxSize();
    
public Vremove(java.lang.Object key)
Removes the mapping with the specified key from this map.

param
key the key of the mapping to remove.
return
the value of the removed mapping or {@code null} if no mapping for the specified key was found.
since
Android 1.0

        poll();
        int index = 0;
        Entry<K, V> entry, last = null;
        if (key != null) {
            index = (key.hashCode() & 0x7FFFFFFF) % elementData.length;
            entry = elementData[index];
            while (entry != null && !key.equals(entry.get())) {
                last = entry;
                entry = entry.next;
            }
        } else {
            entry = elementData[0];
            while (entry != null && !entry.isNull) {
                last = entry;
                entry = entry.next;
            }
        }
        if (entry != null) {
            modCount++;
            if (last == null) {
                elementData[index] = entry.next;
            } else {
                last.next = entry.next;
            }
            elementCount--;
            return entry.value;
        }
        return null;
    
voidremoveEntry(java.util.WeakHashMap$Entry toRemove)

        Entry<K, V> entry, last = null;
        int index = (toRemove.hash & 0x7FFFFFFF) % elementData.length;
        entry = elementData[index];
        // Ignore queued entries which cannot be found, the user could
        // have removed them before they were queued, i.e. using clear()
        while (entry != null) {
            if (toRemove == entry) {
                modCount++;
                if (last == null) {
                    elementData[index] = entry.next;
                } else {
                    last.next = entry.next;
                }
                elementCount--;
                break;
            }
            last = entry;
            entry = entry.next;
        }
    
public intsize()
Returns the number of elements in this map.

return
the number of elements in this map.
since
Android 1.0

        poll();
        return elementCount;
    
public java.util.Collectionvalues()
Returns a collection of the values contained in this map. The collection is backed by this map so changes to one are reflected by the other. The collection supports remove, removeAll, retainAll and clear operations, and it does not support add or addAll operations.

This method returns a collection which is the subclass of AbstractCollection. The iterator method of this subclass returns a "wrapper object" over the iterator of map's entrySet(). The size method wraps the map's size method and the contains method wraps the map's containsValue method.

The collection is created when this method is called at first time and returned in response to all subsequent calls. This method may return different Collection when multiple calls to this method, since it has no synchronization performed.

return
a collection of the values contained in this map.
since
Android 1.0

        poll();
        if (valuesCollection == null) {
            valuesCollection = new AbstractCollection<V>() {
                @Override
                public int size() {
                    return WeakHashMap.this.size();
                }

                @Override
                public void clear() {
                    WeakHashMap.this.clear();
                }

                @Override
                public boolean contains(Object object) {
                    return containsValue(object);
                }

                @Override
                public Iterator<V> iterator() {
                    return new HashIterator<V>(new Entry.Type<V, K, V>() {
                        public V get(Map.Entry<K, V> entry) {
                            return entry.getValue();
                        }
                    });
                }
            };
        }
        return valuesCollection;