Java/Collections Data Structure/Weak Set

Материал из Java эксперт
Перейти к: навигация, поиск

A weak HashSet: element stored in the WeakHashSet might be garbage collected

   <source lang="java">
  

/*

* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.HashSet; import java.util.Iterator; /**

* A weak HashSet. An element stored in the WeakHashSet might be
* garbage collected, if there is no strong reference to this element.
*/

public class WeakHashSet extends HashSet {

   /**
    * Helps to detect garbage collected values.
    */
   ReferenceQueue queue = new ReferenceQueue();
   /**
    * Returns an iterator over the elements in this set.  The elements
    * are returned in no particular order.
    *
    * @return an Iterator over the elements in this set.
    */
   public Iterator iterator() {
       // remove garbage collected elements
       processQueue();
       // get an iterator of the superclass WeakHashSet
       final Iterator i = super.iterator();
       return new Iterator() {
           public boolean hasNext() {
               return i.hasNext();
           }
           public Object next() {
               // unwrap the element
               return getReferenceObject((WeakReference) i.next());
           }
           public void remove() {
               // remove the element from the HashSet
               i.remove();
           }
       };
   }
   /**
    * Returns true if this set contains the specified element.
    *
    * @param o element whose presence in this set is to be tested.
    * @return true if this set contains the specified element.
    */
   public boolean contains(Object o) {
       return super.contains(WeakElement.create(o));
   }
   /**
    * Adds the specified element to this set if it is not already
    * present.
    *
    * @param o element to be added to this set.
    * @return true if the set did not already contain the specified
    * element.
    */
   public boolean add(Object o) {
       processQueue();
       return super.add(WeakElement.create(o, this.queue));
   }
   /**
    * Removes the given element from this set if it is present.
    *
    * @param o object to be removed from this set, if present.
    * @return true if the set contained the specified element.
    */
   public boolean remove(Object o) {
       boolean ret = super.remove(WeakElement.create(o));
       processQueue();
       return ret;
   }
   /**
    * A convenience method to return the object held by the
    * weak reference or null if it does not exist.
    */
   private final Object getReferenceObject(WeakReference ref) {
       return (ref == null) ? null : 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 call it only in the add() method.
    */
   private final void processQueue() {
       WeakElement wv = null;
       while ((wv = (WeakElement) this.queue.poll()) != null) {
           super.remove(wv);
       }
   }
   /**
    * A WeakHashSet stores objects of class WeakElement.
    * A WeakElement wraps the element that should be stored in the WeakHashSet.
    * WeakElement inherits from java.lang.ref.WeakReference.
    * It redefines equals and hashCode which delegate to the corresponding methods
    * of the wrapped element.
    */
   static private class WeakElement extends WeakReference {
       private int hash; /* Hashcode of key, stored here since the key
                              may be tossed by the GC */
       private WeakElement(Object o) {
           super(o);
           hash = o.hashCode();
       }
       private WeakElement(Object o, ReferenceQueue q) {
           super(o, q);
           hash = o.hashCode();
       }
       private static WeakElement create(Object o) {
           return (o == null) ? null : new WeakElement(o);
       }
       private static WeakElement create(Object o, ReferenceQueue q) {
           return (o == null) ? null : new WeakElement(o, q);
       }
       /* A WeakElement is equal to another WeakElement iff they both refer to objects
              that are, in turn, equal according to their own equals methods */
       public boolean equals(Object o) {
           if (this == o)
               return true;
           if (!(o instanceof WeakElement))
               return false;
           Object t = this.get();
           Object u = ((WeakElement) o).get();
           if (t == u) 
               return true;
           if ((t == null) || (u == null))
               return false;
           return t.equals(u);
       }
       public int hashCode() {
           return hash;
       }
   }

}


 </source>
   
  
 
  



Set which holds its members by using of WeakReferences.

   <source lang="java">
  

/*

* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common
* Development and Distribution License("CDDL") (collectively, the
* "License"). You may not use this file except in compliance with the
* License. You can obtain a copy of the License at
* http://www.netbeans.org/cddl-gplv2.html
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
* specific language governing permissions and limitations under the
* License.  When distributing the software, include this License Header
* Notice in each file and include the License file at
* nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the
* License Header, with the fields enclosed by brackets [] replaced by
* your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* Contributor(s):
*
* The Original Software is NetBeans. The Initial Developer of the Original
* Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
* Microsystems, Inc. All Rights Reserved.
*
* If you wish your version of this file to be governed by only the CDDL
* or only the GPL Version 2, indicate your decision by adding
* "[Contributor] elects to include this software in this distribution
* under the [CDDL or GPL Version 2] license." If you do not indicate a
* single choice of license, a recipient has the option to distribute
* your version of this file under either the CDDL, the GPL Version 2 or
* to extend the choice of license to its licensees as provided above.
* However, if you add GPL Version 2 code and therefore, elected the GPL
* Version 2 license, then the option applies only if the new code is
* made subject to such option by the copyright holder.
*/

import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; import java.util.AbstractSet; import java.util.ArrayList; import java.util.Collection; import java.util.ConcurrentModificationException; import java.util.Iterator; import java.util.logging.Level; import java.util.logging.Logger; /** Set which holds its members by using of WeakReferences.

  • MT level: unsafe.
*

Note: as of JDK 6.0 (b51), you can instead use *

 * Set<T> s = Collections.newSetFromMap(new WeakHashMap<T, Boolean>());
 * 
  • @author Ales Novak
  • /

public class WeakSet<E> extends AbstractSet<E> implements Cloneable, Serializable {

   static final long serialVersionUID = 3062376055928236721L;
   /** load factor */
   private float loadFactor;
   /** Number of items. */
   private int size;
   /** Modification count */
   private long modcount;
   /** Reference queue of collected weak refs */
   private transient ReferenceQueue<E> refq;
   /** Count of null in this set */
   long nullCount;
   /** An array of Entries */
   private transient Entry<E>[] entries;
   transient Entry<E> iterChain;
   /** Constructs a new set. */
   public WeakSet() {
       this(11, 0.75f);
   }
   /** Constructs a new set containing the elements in the specified collection.
   * @param c a collection to add
   */
   public WeakSet(Collection<? extends E> c) {
       this();
       addAll(c);
   }
   /** Constructs a new, empty set;
   * @param initialCapacity initial capacity
   */
   public WeakSet(int initialCapacity) {
       this(initialCapacity, 0.75f);
   }
   /** Constructs a new, empty set;
   *
   * @param initialCapacity initial capacity
   * @param loadFactor load factor
   */
   public WeakSet(int initialCapacity, float loadFactor) {
       if ((initialCapacity <= 0) || (loadFactor <= 0)) {
           throw new IllegalArgumentException();
       }
       size = 0;
       modcount = 0;
       this.loadFactor = loadFactor;
       nullCount = 0;
       refq = new ReferenceQueue<E>();
       entries = Entry.createArray(initialCapacity);
       iterChain = null;
   }
   
   /**
    * logs iterator chain (for debugging)
    * @param msg
    */
   void logIterChain(String msg) {
       Logger log = Logger.getLogger(WeakSet.class.getName());
       log.log(Level.FINE, msg);
       if (iterChain == null) {
           log.log(Level.FINE, "Empty");
           return;
       }
       StringBuilder str = new StringBuilder();
       Entry<E> it = iterChain;
       str.append(size + ": ");
       while (it != null) {
           str.append(it.get() + "(" + it.hashcode + ")" + "->");
           it = it.iterChainNext;
       }
       log.log(Level.FINE, str.toString());
   }
   
   /** Adds the specified element to this set if it is not already present.
   *
   * @param o an Object to add
   */
   public boolean add(E o) {
       if (o == null) {
           size++;
           nullCount++;
           modcount++;
           return true;
       }
       Entry e = object2Entry(o);
       if (e != null) {
           return false;
       }
       modcount++;
       size++;
       int hash = hashIt(o);
       Entry<E> next = entries[hash];
       iterChain = entries[hash] = new Entry<E>(this, o, refq, next, iterChain);
       rehash();
       return true;
   }
   /** Removes all of the elements from this set. */
   public void clear() {
       for (int i = 0; i < entries.length; i++) {
           entries[i] = null;
       }
       nullCount = 0;
       modcount++;
       size = 0;
       iterChain = null;
   }
   /** Returns a shallow copy of this WeakSet instance: the elements themselves are not cloned. */
   public Object clone() {
       WeakSet<E> nws = new WeakSet<E>(1, loadFactor);
       nws.size = size;
       nws.nullCount = nullCount;
       Entry<E>[] cloned = Entry.createArray(entries.length);
       nws.entries = cloned;
       for (int i = 0; i < cloned.length; i++) {
           Object ref;
           if ((entries[i] == null) || ((ref = entries[i].get()) == null)) {
               cloned[i] = null;
           } else {
               cloned[i] = ((entries[i] == null) ? null : entries[i].clone(nws.refq));
               ref = null;
           }
           // chains into nws iterator chain
           Entry<E> entry = cloned[i];
           while (entry != null) {
               entry.chainIntoIter(nws.iterChain);
               nws.iterChain = entry;
               entry = entry.next;
           }
       }
       return nws;
   }
   /** Returns true if this set contains the specified element.
   *
   * @param o an Object to examine
   */
   public boolean contains(Object o) {
       if (o == null) {
           return nullCount > 0;
       }
       return object2Entry(o) != null;
   }
   /** Returns true if this set contains no elements.
   */
   public boolean isEmpty() {
       return ((nullCount == 0) && (size() == 0));
   }
   /** Returns an iterator over the elements in this set. */
   public Iterator<E> iterator() {
       return new WeakSetIterator();
   }
   /** Removes the given element from this set if it is present.
   *
   * @param o an Object to remove
   * @return true if and only if the Object was successfuly removed.
   */
   public boolean remove(Object o) {
       if (o == null) {
           if (nullCount > 0) {
               nullCount--;
               modcount++;
               size--;
           }
           return true;
       }
       Entry e = object2Entry(o);
       if (e != null) {
           modcount++;
           size--;
           e.remove();
           rehash();
           return true;
       }
       return false;
   }
   /** @return the number of elements in this set (its cardinality). */
   public int size() {
       checkRefQueue();
       return size;
   }
   public <T> T[] toArray(T[] array) {
       ArrayList<E> list = new ArrayList<E>(array.length);
       Iterator<E> it = iterator();
       while (it.hasNext()) {
           list.add(it.next());
       }
       return list.toArray(array);
   }
   public Object[] toArray() {
       ArrayList<E> list = new ArrayList<E>();
       Iterator<E> it = iterator();
       while (it.hasNext()) {
           list.add(it.next());
       }
       return list.toArray();
   }
   // #14772
   public String toString() {
       StringBuffer buf = new StringBuffer();
       Iterator e = iterator();
       buf.append("[");
       while (e.hasNext()) {
           buf.append(String.valueOf(e.next()));
           if (e.hasNext()) {
               buf.append(", ");
           }
       }
       buf.append("]");
       return buf.toString();
   }
   /** Checks if the queue is empty if not pending weak refs are removed. */
   void checkRefQueue() {
       for (;;) {
           Entry entry = Entry.class.cast(refq.poll());
           if (entry == null) {
               break;
           }
           entry.remove();
           size--;
       }
   }
   /** @return modcount */
   long modCount() {
       return modcount;
   }
   /** @return an index to entries array */
   int hashIt(Object o) {
       return (o.hashCode() & 0x7fffffff) % entries.length;
   }
   /** rehashes this Set */
   void rehash() {
       /*
       float currentLF = ((float) size) / ((float) entries.length);
       if (currentLF < loadFactor) {
         return;
       }
       */
   }
   /** @return an Entry with given object */
   private Entry object2Entry(Object o) {
       checkRefQueue(); // clear ref q
       int hash = hashIt(o);
       Entry e = entries[hash];
       if (e == null) {
           return null;
       }
       while ((e != null) && !e.equals(o)) {
           e = e.next;
       }
       return e;
   }
   private void writeObject(ObjectOutputStream obtos)
   throws IOException {
       obtos.defaultWriteObject();
       obtos.writeObject(toArray());
   }
   @SuppressWarnings("unchecked")
   private void readObject(ObjectInputStream obtis) throws IOException, ClassNotFoundException {
       obtis.defaultReadObject();
       Object[] arr = (Object[]) obtis.readObject();
       entries = new Entry[(int) (size * 1.5)];
       refq = new ReferenceQueue<E>();
       for (int i = 0; i < arr.length; i++) {
           add((E)arr[i]);
       }
   }
   class WeakSetIterator implements Iterator<E> {
       Entry<E> current;
       Entry<E> next;
       E currentObj;
       E nextObj;
       final long myModcount;
       long myNullCount;
       WeakSetIterator() {
           myModcount = modCount();
           myNullCount = nullCount;
           current = null;
           next = null;
           Entry<E> ee = iterChain;
           if (ee == null) {
               return;
           }
           E o = ee.get();
           while (ee.isEnqueued()) {
               ee = ee.iterChainNext;
               if (ee == null) {
                   return;
               }
               o = ee.get();
           }
           nextObj = o;
           next = ee;
       }
       public boolean hasNext() {
           checkModcount();
           return ((myNullCount > 0) || (next != null));
       }
       public E next() {
           checkModcount();
           checkRefQueue();
           if (myNullCount > 0) {
               myNullCount--;
               return null;
           } else {
               if (next == null) {
                   throw new java.util.NoSuchElementException();
               }
               current = next;
               currentObj = nextObj;
               // move to next requested
               do {
                   next = next.iterChainNext;
                   if (next == null) {
                       break;
                   }
                   nextObj = next.get();
               } while (next.isEnqueued());
               return currentObj;
           }
       }
       public void remove() {
           checkModcount();
           if (current == null) {
               throw new IllegalStateException();
           }
           current.remove();
           size--;
       }
       void checkModcount() {
           if (myModcount != modCount()) {
               throw new ConcurrentModificationException();
           }
       }
   }
   /** Entries of this set */
   static class Entry<E> extends WeakReference<E> {
       /** reference to outer WeakSet */
       private WeakSet<E> set;
       // double linked list
       Entry<E> prev;
       Entry<E> next;
       private final int hashcode;
       Entry<E> iterChainNext;
       Entry<E> iterChainPrev;
       Entry(WeakSet<E> set, E referenced, ReferenceQueue<E> q, Entry<E> next, Entry<E> nextInIter) {
           super(referenced, q);
           this.set = set;
           this.next = next;
           this.prev = null;
           if (next != null) {
               next.prev = this;
           }
           if (referenced != null) {
               hashcode = set.hashIt(referenced);
           } else {
               hashcode = 0;
           }
           chainIntoIter(nextInIter);
       }
       @SuppressWarnings("unchecked")
       static final <E> Entry<E>[] createArray(int size) {
           return new Entry[size];
       }
       void chainIntoIter(Entry<E> nextInIter) {
           iterChainNext = nextInIter;
           if (nextInIter != null) {
               nextInIter.iterChainPrev = this;
           }
       }
       /** deques itself */
       void remove() {
           if (prev != null) {
               prev.next = next;
           }
           if (next != null) {
               next.prev = prev;
           }
           if (iterChainNext != null) {
               iterChainNext.iterChainPrev = iterChainPrev;
           }
           if (iterChainPrev != null) {
               iterChainPrev.iterChainNext = iterChainNext;
           } else { // root
               set.iterChain = iterChainNext;
           }
           if (set.entries[hashcode] == this) {
               set.entries[hashcode] = next;
           }
           prev = null;
           next = null;
           iterChainNext = null;
           iterChainPrev = null;
       }
       public int hashCode() {
           return hashcode;
       }
       public boolean equals(Object o) {
           Object oo = get();
           if (oo == null) {
               return false;
           } else {
               return oo.equals(o);
           }
       }
       public Entry<E> clone(ReferenceQueue<E> q) {
           return new Entry<E>(set, get(), q, next != null ? next.clone(q) : null, null);
       }
   }

}


 </source>
   
  
 
  



Weak HashSet

   <source lang="java">
 

/*

* 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.HashSet; import java.util.Iterator; /**

* A weak HashSet. An element stored in the WeakHashSet might be
* garbage collected, if there is no strong reference to this element.
*/

public class WeakHashSet extends HashSet {

   /**
    * Helps to detect garbage collected values.
    */
   ReferenceQueue queue = new ReferenceQueue();
   /**
    * Returns an iterator over the elements in this set.  The elements
    * are returned in no particular order.
    *
    * @return an Iterator over the elements in this set.
    */
   public Iterator iterator() {
       // remove garbage collected elements
       processQueue();
       // get an iterator of the superclass WeakHashSet
       final Iterator i = super.iterator();
       return new Iterator() {
           public boolean hasNext() {
               return i.hasNext();
           }
           public Object next() {
               // unwrap the element
               return getReferenceObject((WeakReference) i.next());
           }
           public void remove() {
               // remove the element from the HashSet
               i.remove();
           }
       };
   }
   /**
    * Returns true if this set contains the specified element.
    *
    * @param o element whose presence in this set is to be tested.
    * @return true if this set contains the specified element.
    */
   public boolean contains(Object o) {
       return super.contains(WeakElement.create(o));
   }
   /**
    * Adds the specified element to this set if it is not already
    * present.
    *
    * @param o element to be added to this set.
    * @return true if the set did not already contain the specified
    * element.
    */
   public boolean add(Object o) {
       processQueue();
       return super.add(WeakElement.create(o, this.queue));
   }
   /**
    * Removes the given element from this set if it is present.
    *
    * @param o object to be removed from this set, if present.
    * @return true if the set contained the specified element.
    */
   public boolean remove(Object o) {
       boolean ret = super.remove(WeakElement.create(o));
       processQueue();
       return ret;
   }
   /**
    * A convenience method to return the object held by the
    * weak reference or null if it does not exist.
    */
   private final Object getReferenceObject(WeakReference ref) {
       return (ref == null) ? null : 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 call it only in the add() method.
    */
   private final void processQueue() {
       WeakElement wv = null;
       while ((wv = (WeakElement) this.queue.poll()) != null) {
           super.remove(wv);
       }
   }
   /**
    * A WeakHashSet stores objects of class WeakElement.
    * A WeakElement wraps the element that should be stored in the WeakHashSet.
    * WeakElement inherits from java.lang.ref.WeakReference.
    * It redefines equals and hashCode which delegate to the corresponding methods
    * of the wrapped element.
    */
   static private class WeakElement extends WeakReference {
       private int hash; /* Hashcode of key, stored here since the key
                              may be tossed by the GC */
       private WeakElement(Object o) {
           super(o);
           hash = o.hashCode();
       }
       private WeakElement(Object o, ReferenceQueue q) {
           super(o, q);
           hash = o.hashCode();
       }
       private static WeakElement create(Object o) {
           return (o == null) ? null : new WeakElement(o);
       }
       private static WeakElement create(Object o, ReferenceQueue q) {
           return (o == null) ? null : new WeakElement(o, q);
       }
       /* A WeakElement is equal to another WeakElement iff they both refer to objects
              that are, in turn, equal according to their own equals methods */
       public boolean equals(Object o) {
           if (this == o)
               return true;
           if (!(o instanceof WeakElement))
               return false;
           Object t = this.get();
           Object u = ((WeakElement) o).get();
           if (t == u) 
               return true;
           if ((t == null) || (u == null))
               return false;
           return t.equals(u);
       }
       public int hashCode() {
           return hash;
       }
   }

}


 </source>
   
  
 
  



Weak HashSet from objectweb jac

   <source lang="java">
 

// Revised from objectweb jac import java.lang.Cloneable; import java.util.AbstractSet; import java.util.Collection; import java.util.Iterator; import java.util.Set; import java.util.WeakHashMap;

public class WeakHashSet extends AbstractSet

   implements Set

{

   private transient WeakHashMap map;
   public WeakHashSet() {
       map = new WeakHashMap();
   }
   public WeakHashSet(Collection c) {
       map = new WeakHashMap(Math.max((int) (c.size()/.75f) + 1, 16));
       addAll(c);
   }
   public WeakHashSet(int initialCapacity, float loadFactor) {
       map = new WeakHashMap(initialCapacity, loadFactor);
   }
   public WeakHashSet(int initialCapacity) {
       map = new WeakHashMap(initialCapacity);
   }
   public Iterator iterator() {
       return map.keySet().iterator();
   }
   public int size() {
       return map.size();
   }
   public boolean isEmpty() {
       return map.isEmpty();
   }
   public boolean contains(Object o) {
       return map.containsKey(o);
   }
   public boolean add(Object o) {
       return map.put(o, Boolean.TRUE)==null;
   }
   public boolean remove(Object o) {
       return map.remove(o)==Boolean.TRUE;
   }
   public void clear() {
       map.clear();
   }

}


 </source>
   
  
 
  



Weak HashSet from TJDO

   <source lang="java">
 

/*

* Copyright 2004 (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: WeakHashSet.java,v 1.1 2004/08/09 23:53:35 jackknifebarber Exp $
*/

import java.util.AbstractSet; import java.util.Collection; import java.util.Iterator; import java.util.Set; import java.util.WeakHashMap;

/**

* A Set implementation with weak elements.
* This class implements the Set interface, backed by a hash table with
* weak keys (actually a WeakHashMap instance).
* An element in a WeakHashSet will automatically be removed when it
* is no longer in ordinary use.
* More precisely, the presence of an element will not prevent it from being
* discarded by the garbage collector, that is, made finalizable, finalized,
* and then reclaimed.
* When a element has been discarded it is effectively removed from the set,
* so this class behaves somewhat differently than other Set
* implementations.
* <p>
* The null element is supported.
* This class has performance characteristics similar to those of the
* HashSet class, and has the same efficiency parameters of
* initial capacity and load factor.
* <p>
* Like most collection classes, this class is not synchronized.
* A synchronized WeakHashSet may be constructed using the
* Collections.synchronizedSet method.
* <p>
* This class is intended primarily for use with objects whose
* equals methods test for object identity using the
* == operator.
* Once such an object is discarded it can never be recreated, so it is
* impossible to do a lookup of that key in a WeakHashSet at some later
* time and be surprised that its entry has been removed.
* This class will work perfectly well with objects whose equals
* methods are not based upon object identity, such as String
* instances.
* With such recreatable objects however, the automatic removal of
* WeakHashSet elements that have been discarded may prove to be
* confusing.
* <p>
* The behavior of the WeakHashSet class depends in part upon the
* actions of the garbage collector, so several familiar (though not required)
* Set invariants do not hold for this class.
* Because the garbage collector may discard elements at any time, a
* WeakHashSet may behave as though an unknown thread is silently
* removing elements.
* In particular, even if you synchronize on a WeakHashSet instance and
* invoke none of its mutator methods, it is possible for the size
* method to return smaller values over time, for the isEmpty method to
* return false and then true, for the contains
* method to return true and later false for a given object,
* for the add method to return true and the remove
* method to return false for an element that previously appeared to be
* in the set, and for successive examinations of the set to yield successively
* smaller numbers of elements.
* <p>
* Each element in a WeakHashSet is stored indirectly as the referent
* of a weak reference.
* Therefore an element will automatically be removed only after the weak
* references to it, both inside and outside of the set, have been cleared by
* the garbage collector.
* <p>
* The iterators returned by this class are fail-fast: if the set is
* structurally modified at any time after the iterator is created, in any way
* except through the iterator"s own remove or add methods,
* the iterator will throw a ConcurrentModificationException.
* Thus, in the face of concurrent modification, the iterator fails quickly and
* cleanly, rather than risking arbitrary, non-deterministic behavior at an
* undetermined time in the future.
* <p>
* Note that the fail-fast behavior of an iterator cannot be guaranteed
* as it is, generally speaking, impossible to make any hard guarantees in the
* presence of unsynchronized concurrent modification.
* Fail-fast iterators throw ConcurrentModificationException on a
* best-effort basis.
* Therefore, it would be wrong to write a program that depended on this
* exception for its correctness:  the fail-fast behavior of iterators
* should be used only to detect bugs.
*
*
* @author   (borrowing
*          liberally from java.util.HashSet)
* @version $Revision: 1.1 $
*/

public class WeakHashSet extends AbstractSet implements Set {

   /* Dummy value to associate with an Object in the backing Map. */
   private static final Object PRESENT = new Object();
   private final WeakHashMap map;
   /**
    * Constructs a new, empty set; the backing WeakHashMap instance has
    * default initial capacity (16) and load factor (0.75).
    */
   public WeakHashSet()
   {
       map = new WeakHashMap();
   }
   /**
    * Constructs a new set containing the elements in the specified
    * collection.  The WeakHashMap is created with default load factor
    * (0.75) and an initial capacity sufficient to contain the elements in
    * the specified collection.
    *
    * @param c the collection whose elements are to be placed into this set.
    * @throws NullPointerException   if the specified collection is null.
    */
   public WeakHashSet(Collection c)
   {
       map = new WeakHashMap(Math.max((int)(c.size() / .75f) + 1, 16));
       addAll(c);
   }
   /**
    * Constructs a new, empty set; the backing WeakHashMap instance has
    * the specified initial capacity and the specified load factor.
    *
    * @param      initialCapacity   the initial capacity of the hash map.
    * @param      loadFactor        the load factor of the hash map.
    * @throws     IllegalArgumentException if the initial capacity is less
    *             than zero, or if the load factor is nonpositive.
    */
   public WeakHashSet(int initialCapacity, float loadFactor)
   {
       map = new WeakHashMap(initialCapacity, loadFactor);
   }
   /**
    * Constructs a new, empty set; the backing WeakHashMap instance has
    * the specified initial capacity and default load factor, which is
    * 0.75.
    *
    * @param      initialCapacity   the initial capacity of the hash table.
    * @throws     IllegalArgumentException if the initial capacity is less
    *             than zero.
    */
   public WeakHashSet(int initialCapacity)
   {
       map = new WeakHashMap(initialCapacity);
   }
   /**
    * Returns an iterator over the elements in this set.  The elements
    * are returned in no particular order.
    *
    * @return an Iterator over the elements in this set.
    * @see "java.util.ConcurrentModificationException"
    */
   public Iterator iterator()
   {
       return map.keySet().iterator();
   }
   /**
    * Returns the number of elements in this set (its cardinality).
    *
    * @return the number of elements.
    */
   public int size()
   {
       return map.size();
   }
   /**
    * Indicates whether the set is empty.
    *
    * @return true if the set contains no elements.
    */
   public boolean isEmpty()
   {
       return map.isEmpty();
   }
   /**
    * Indicates whether the set contains the specified element.
    *
    * @param o the element to specify.
    * @return true if the set contains the specified element.
    */
   public boolean contains(Object o)
   {
       return map.containsKey(o);
   }
   /**
    * Adds the specified element to the set if it is not already
    * present.
    *
    * @param o the element to be added.
    * @return true if the set did not already contain the specified
    * element.
    */
   public boolean add(Object o)
   {
       return map.put(o, PRESENT) == null;
   }
   /**
    * Removes the specified element from the set if it is present.
    *
    * @param o the element to be removed.
    * @return true if the set contained the specified element.
    */
   public boolean remove(Object o)
   {
       return map.remove(o) == PRESENT;
   }
   /**
    * Removes all of the elements from the set.
    */
   public void clear()
   {
       map.clear();
   }

}


 </source>