1. /*
  2. * @(#)HashSet.java 1.19 00/02/02
  3. *
  4. * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. package java.util;
  11. /**
  12. * This class implements the <tt>Set</tt> interface, backed by a hash table
  13. * (actually a <tt>HashMap</tt> instance). It makes no guarantees as to the
  14. * iteration order of the set; in particular, it does not guarantee that the
  15. * order will remain constant over time. This class permits the <tt>null</tt>
  16. * element.<p>
  17. *
  18. * This class offers constant time performance for the basic operations
  19. * (<tt>add</tt>, <tt>remove</tt>, <tt>contains</tt> and <tt>size</tt>),
  20. * assuming the hash function disperses the elements properly among the
  21. * buckets. Iterating over this set requires time proportional to the sum of
  22. * the <tt>HashSet</tt> instance's size (the number of elements) plus the
  23. * "capacity" of the backing <tt>HashMap</tt> instance (the number of
  24. * buckets). Thus, it's very important not to set the intial capacity too
  25. * high (or the load factor too low) if iteration performance is important.<p>
  26. *
  27. * <b>Note that this implementation is not synchronized.</b> If multiple
  28. * threads access a set concurrently, and at least one of the threads modifies
  29. * the set, it <i>must</i> be synchronized externally. This is typically
  30. * accomplished by synchronizing on some object that naturally encapsulates
  31. * the set. If no such object exists, the set should be "wrapped" using the
  32. * <tt>Collections.synchronizedSet</tt> method. This is best done at creation
  33. * time, to prevent accidental unsynchronized access to the <tt>HashSet</tt>
  34. * instance:
  35. *
  36. * <pre>
  37. * Set s = Collections.synchronizedSet(new HashSet(...));
  38. * </pre><p>
  39. *
  40. * The iterators returned by this class's <tt>iterator</tt> method are
  41. * <i>fail-fast</i>: if the set is modified at any time after the iterator is
  42. * created, in any way except through the iterator's own <tt>remove</tt>
  43. * method, the Iterator throws a <tt>ConcurrentModificationException</tt>.
  44. * Thus, in the face of concurrent modification, the iterator fails quickly
  45. * and cleanly, rather than risking arbitrary, non-deterministic behavior at
  46. * an undetermined time in the future.
  47. *
  48. * @author Josh Bloch
  49. * @version 1.19, 02/02/00
  50. * @see Collection
  51. * @see Set
  52. * @see TreeSet
  53. * @see Collections#synchronizedSet(Set)
  54. * @see HashMap
  55. * @since 1.2
  56. */
  57. public class HashSet extends AbstractSet
  58. implements Set, Cloneable, java.io.Serializable
  59. {
  60. private transient HashMap map;
  61. // Dummy value to associate with an Object in the backing Map
  62. private static final Object PRESENT = new Object();
  63. /**
  64. * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
  65. * default capacity and load factor, which is <tt>0.75</tt>.
  66. */
  67. public HashSet() {
  68. map = new HashMap();
  69. }
  70. /**
  71. * Constructs a new set containing the elements in the specified
  72. * collection. The capacity of the backing <tt>HashMap</tt> instance is
  73. * twice the size of the specified collection or eleven (whichever is
  74. * greater), and the default load factor (which is <tt>0.75</tt>) is used.
  75. *
  76. * @param c the collection whose elements are to be placed into this set.
  77. */
  78. public HashSet(Collection c) {
  79. map = new HashMap(Math.max(2*c.size(), 11));
  80. addAll(c);
  81. }
  82. /**
  83. * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
  84. * the specified initial capacity and the specified load factor.
  85. *
  86. * @param initialCapacity the initial capacity of the hash map.
  87. * @param loadFactor the load factor of the hash map.
  88. * @throws IllegalArgumentException if the initial capacity is less
  89. * than zero, or if the load factor is nonpositive.
  90. */
  91. public HashSet(int initialCapacity, float loadFactor) {
  92. map = new HashMap(initialCapacity, loadFactor);
  93. }
  94. /**
  95. * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
  96. * the specified initial capacity and default load factor, which is
  97. * <tt>0.75</tt>.
  98. *
  99. * @param initialCapacity the initial capacity of the hash table.
  100. * @throws IllegalArgumentException if the initial capacity is less
  101. * than zero.
  102. */
  103. public HashSet(int initialCapacity) {
  104. map = new HashMap(initialCapacity);
  105. }
  106. /**
  107. * Returns an iterator over the elements in this set. The elements
  108. * are returned in no particular order.
  109. *
  110. * @return an Iterator over the elements in this set.
  111. * @see ConcurrentModificationException
  112. */
  113. public Iterator iterator() {
  114. return map.keySet().iterator();
  115. }
  116. /**
  117. * Returns the number of elements in this set (its cardinality).
  118. *
  119. * @return the number of elements in this set (its cardinality).
  120. */
  121. public int size() {
  122. return map.size();
  123. }
  124. /**
  125. * Returns <tt>true</tt> if this set contains no elements.
  126. *
  127. * @return <tt>true</tt> if this set contains no elements.
  128. */
  129. public boolean isEmpty() {
  130. return map.isEmpty();
  131. }
  132. /**
  133. * Returns <tt>true</tt> if this set contains the specified element.
  134. *
  135. * @param o element whose presence in this set is to be tested.
  136. * @return <tt>true</tt> if this set contains the specified element.
  137. */
  138. public boolean contains(Object o) {
  139. return map.containsKey(o);
  140. }
  141. /**
  142. * Adds the specified element to this set if it is not already
  143. * present.
  144. *
  145. * @param o element to be added to this set.
  146. * @return <tt>true</tt> if the set did not already contain the specified
  147. * element.
  148. */
  149. public boolean add(Object o) {
  150. return map.put(o, PRESENT)==null;
  151. }
  152. /**
  153. * Removes the given element from this set if it is present.
  154. *
  155. * @param o object to be removed from this set, if present.
  156. * @return <tt>true</tt> if the set contained the specified element.
  157. */
  158. public boolean remove(Object o) {
  159. return map.remove(o)==PRESENT;
  160. }
  161. /**
  162. * Removes all of the elements from this set.
  163. */
  164. public void clear() {
  165. map.clear();
  166. }
  167. /**
  168. * Returns a shallow copy of this <tt>HashSet</tt> instance: the elements
  169. * themselves are not cloned.
  170. *
  171. * @return a shallow copy of this set.
  172. */
  173. public Object clone() {
  174. try {
  175. HashSet newSet = (HashSet)super.clone();
  176. newSet.map = (HashMap)map.clone();
  177. return newSet;
  178. } catch (CloneNotSupportedException e) {
  179. throw new InternalError();
  180. }
  181. }
  182. /**
  183. * Save the state of this <tt>HashSet</tt> instance to a stream (that is,
  184. * serialize this set).
  185. *
  186. * @serialData The capacity of the backing <tt>HashMap</tt> instance
  187. * (int), and its load factor (float) are emitted, followed by
  188. * the size of the set (the number of elements it contains)
  189. * (int), followed by all of its elements (each an Object) in
  190. * no particular order.
  191. */
  192. private synchronized void writeObject(java.io.ObjectOutputStream s)
  193. throws java.io.IOException {
  194. // Write out any hidden serialization magic
  195. s.defaultWriteObject();
  196. // Write out HashMap capacity and load factor
  197. s.writeInt(map.capacity());
  198. s.writeFloat(map.loadFactor());
  199. // Write out size
  200. s.writeInt(map.size());
  201. // Write out all elements in the proper order.
  202. for (Iterator i=map.keySet().iterator(); i.hasNext(); )
  203. s.writeObject(i.next());
  204. }
  205. /**
  206. * Reconstitute the <tt>HashSet</tt> instance from a stream (that is,
  207. * deserialize it).
  208. */
  209. private synchronized void readObject(java.io.ObjectInputStream s)
  210. throws java.io.IOException, ClassNotFoundException {
  211. // Read in any hidden serialization magic
  212. s.defaultReadObject();
  213. // Read in HashMap capacity and load factor and create backing HashMap
  214. int capacity = s.readInt();
  215. float loadFactor = s.readFloat();
  216. map = new HashMap(capacity, loadFactor);
  217. // Read in size
  218. int size = s.readInt();
  219. // Read in all elements in the proper order.
  220. for (int i=0; i<size; i++) {
  221. Object e = s.readObject();
  222. map.put(e, PRESENT);
  223. }
  224. }
  225. }