Save This Page
Home » openjdk-7 » java » util » [javadoc | source]
    1   /*
    2    * Copyright 1994-2006 Sun Microsystems, Inc.  All Rights Reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any questions.
   24    */
   25   
   26   package java.util;
   27   import java.io;
   28   
   29   /**
   30    * This class implements a hash table, which maps keys to values. Any
   31    * non-<code>null</code> object can be used as a key or as a value. <p>
   32    *
   33    * To successfully store and retrieve objects from a hashtable, the
   34    * objects used as keys must implement the <code>hashCode</code>
   35    * method and the <code>equals</code> method. <p>
   36    *
   37    * An instance of <code>Hashtable</code> has two parameters that affect its
   38    * performance: <i>initial capacity</i> and <i>load factor</i>.  The
   39    * <i>capacity</i> is the number of <i>buckets</i> in the hash table, and the
   40    * <i>initial capacity</i> is simply the capacity at the time the hash table
   41    * is created.  Note that the hash table is <i>open</i>: in the case of a "hash
   42    * collision", a single bucket stores multiple entries, which must be searched
   43    * sequentially.  The <i>load factor</i> is a measure of how full the hash
   44    * table is allowed to get before its capacity is automatically increased.
   45    * The initial capacity and load factor parameters are merely hints to
   46    * the implementation.  The exact details as to when and whether the rehash
   47    * method is invoked are implementation-dependent.<p>
   48    *
   49    * Generally, the default load factor (.75) offers a good tradeoff between
   50    * time and space costs.  Higher values decrease the space overhead but
   51    * increase the time cost to look up an entry (which is reflected in most
   52    * <tt>Hashtable</tt> operations, including <tt>get</tt> and <tt>put</tt>).<p>
   53    *
   54    * The initial capacity controls a tradeoff between wasted space and the
   55    * need for <code>rehash</code> operations, which are time-consuming.
   56    * No <code>rehash</code> operations will <i>ever</i> occur if the initial
   57    * capacity is greater than the maximum number of entries the
   58    * <tt>Hashtable</tt> will contain divided by its load factor.  However,
   59    * setting the initial capacity too high can waste space.<p>
   60    *
   61    * If many entries are to be made into a <code>Hashtable</code>,
   62    * creating it with a sufficiently large capacity may allow the
   63    * entries to be inserted more efficiently than letting it perform
   64    * automatic rehashing as needed to grow the table. <p>
   65    *
   66    * This example creates a hashtable of numbers. It uses the names of
   67    * the numbers as keys:
   68    * <pre>   {@code
   69    *   Hashtable<String, Integer> numbers
   70    *     = new Hashtable<String, Integer>();
   71    *   numbers.put("one", 1);
   72    *   numbers.put("two", 2);
   73    *   numbers.put("three", 3);}</pre>
   74    *
   75    * <p>To retrieve a number, use the following code:
   76    * <pre>   {@code
   77    *   Integer n = numbers.get("two");
   78    *   if (n != null) {
   79    *     System.out.println("two = " + n);
   80    *   }}</pre>
   81    *
   82    * <p>The iterators returned by the <tt>iterator</tt> method of the collections
   83    * returned by all of this class's "collection view methods" are
   84    * <em>fail-fast</em>: if the Hashtable is structurally modified at any time
   85    * after the iterator is created, in any way except through the iterator's own
   86    * <tt>remove</tt> method, the iterator will throw a {@link
   87    * ConcurrentModificationException}.  Thus, in the face of concurrent
   88    * modification, the iterator fails quickly and cleanly, rather than risking
   89    * arbitrary, non-deterministic behavior at an undetermined time in the future.
   90    * The Enumerations returned by Hashtable's keys and elements methods are
   91    * <em>not</em> fail-fast.
   92    *
   93    * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
   94    * as it is, generally speaking, impossible to make any hard guarantees in the
   95    * presence of unsynchronized concurrent modification.  Fail-fast iterators
   96    * throw <tt>ConcurrentModificationException</tt> on a best-effort basis.
   97    * Therefore, it would be wrong to write a program that depended on this
   98    * exception for its correctness: <i>the fail-fast behavior of iterators
   99    * should be used only to detect bugs.</i>
  100    *
  101    * <p>As of the Java 2 platform v1.2, this class was retrofitted to
  102    * implement the {@link Map} interface, making it a member of the
  103    * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  104    *
  105    * Java Collections Framework</a>.  Unlike the new collection
  106    * implementations, {@code Hashtable} is synchronized.  If a
  107    * thread-safe implementation is not needed, it is recommended to use
  108    * {@link HashMap} in place of {@code Hashtable}.  If a thread-safe
  109    * highly-concurrent implementation is desired, then it is recommended
  110    * to use {@link java.util.concurrent.ConcurrentHashMap} in place of
  111    * {@code Hashtable}.
  112    *
  113    * @author  Arthur van Hoff
  114    * @author  Josh Bloch
  115    * @author  Neal Gafter
  116    * @see     Object#equals(java.lang.Object)
  117    * @see     Object#hashCode()
  118    * @see     Hashtable#rehash()
  119    * @see     Collection
  120    * @see     Map
  121    * @see     HashMap
  122    * @see     TreeMap
  123    * @since JDK1.0
  124    */
  125   public class Hashtable<K,V>
  126       extends Dictionary<K,V>
  127       implements Map<K,V>, Cloneable, java.io.Serializable {
  128   
  129       /**
  130        * The hash table data.
  131        */
  132       private transient Entry[] table;
  133   
  134       /**
  135        * The total number of entries in the hash table.
  136        */
  137       private transient int count;
  138   
  139       /**
  140        * The table is rehashed when its size exceeds this threshold.  (The
  141        * value of this field is (int)(capacity * loadFactor).)
  142        *
  143        * @serial
  144        */
  145       private int threshold;
  146   
  147       /**
  148        * The load factor for the hashtable.
  149        *
  150        * @serial
  151        */
  152       private float loadFactor;
  153   
  154       /**
  155        * The number of times this Hashtable has been structurally modified
  156        * Structural modifications are those that change the number of entries in
  157        * the Hashtable or otherwise modify its internal structure (e.g.,
  158        * rehash).  This field is used to make iterators on Collection-views of
  159        * the Hashtable fail-fast.  (See ConcurrentModificationException).
  160        */
  161       private transient int modCount = 0;
  162   
  163       /** use serialVersionUID from JDK 1.0.2 for interoperability */
  164       private static final long serialVersionUID = 1421746759512286392L;
  165   
  166       /**
  167        * Constructs a new, empty hashtable with the specified initial
  168        * capacity and the specified load factor.
  169        *
  170        * @param      initialCapacity   the initial capacity of the hashtable.
  171        * @param      loadFactor        the load factor of the hashtable.
  172        * @exception  IllegalArgumentException  if the initial capacity is less
  173        *             than zero, or if the load factor is nonpositive.
  174        */
  175       public Hashtable(int initialCapacity, float loadFactor) {
  176           if (initialCapacity < 0)
  177               throw new IllegalArgumentException("Illegal Capacity: "+
  178                                                  initialCapacity);
  179           if (loadFactor <= 0 || Float.isNaN(loadFactor))
  180               throw new IllegalArgumentException("Illegal Load: "+loadFactor);
  181   
  182           if (initialCapacity==0)
  183               initialCapacity = 1;
  184           this.loadFactor = loadFactor;
  185           table = new Entry[initialCapacity];
  186           threshold = (int)(initialCapacity * loadFactor);
  187       }
  188   
  189       /**
  190        * Constructs a new, empty hashtable with the specified initial capacity
  191        * and default load factor (0.75).
  192        *
  193        * @param     initialCapacity   the initial capacity of the hashtable.
  194        * @exception IllegalArgumentException if the initial capacity is less
  195        *              than zero.
  196        */
  197       public Hashtable(int initialCapacity) {
  198           this(initialCapacity, 0.75f);
  199       }
  200   
  201       /**
  202        * Constructs a new, empty hashtable with a default initial capacity (11)
  203        * and load factor (0.75).
  204        */
  205       public Hashtable() {
  206           this(11, 0.75f);
  207       }
  208   
  209       /**
  210        * Constructs a new hashtable with the same mappings as the given
  211        * Map.  The hashtable is created with an initial capacity sufficient to
  212        * hold the mappings in the given Map and a default load factor (0.75).
  213        *
  214        * @param t the map whose mappings are to be placed in this map.
  215        * @throws NullPointerException if the specified map is null.
  216        * @since   1.2
  217        */
  218       public Hashtable(Map<? extends K, ? extends V> t) {
  219           this(Math.max(2*t.size(), 11), 0.75f);
  220           putAll(t);
  221       }
  222   
  223       /**
  224        * Returns the number of keys in this hashtable.
  225        *
  226        * @return  the number of keys in this hashtable.
  227        */
  228       public synchronized int size() {
  229           return count;
  230       }
  231   
  232       /**
  233        * Tests if this hashtable maps no keys to values.
  234        *
  235        * @return  <code>true</code> if this hashtable maps no keys to values;
  236        *          <code>false</code> otherwise.
  237        */
  238       public synchronized boolean isEmpty() {
  239           return count == 0;
  240       }
  241   
  242       /**
  243        * Returns an enumeration of the keys in this hashtable.
  244        *
  245        * @return  an enumeration of the keys in this hashtable.
  246        * @see     Enumeration
  247        * @see     #elements()
  248        * @see     #keySet()
  249        * @see     Map
  250        */
  251       public synchronized Enumeration<K> keys() {
  252           return this.<K>getEnumeration(KEYS);
  253       }
  254   
  255       /**
  256        * Returns an enumeration of the values in this hashtable.
  257        * Use the Enumeration methods on the returned object to fetch the elements
  258        * sequentially.
  259        *
  260        * @return  an enumeration of the values in this hashtable.
  261        * @see     java.util.Enumeration
  262        * @see     #keys()
  263        * @see     #values()
  264        * @see     Map
  265        */
  266       public synchronized Enumeration<V> elements() {
  267           return this.<V>getEnumeration(VALUES);
  268       }
  269   
  270       /**
  271        * Tests if some key maps into the specified value in this hashtable.
  272        * This operation is more expensive than the {@link #containsKey
  273        * containsKey} method.
  274        *
  275        * <p>Note that this method is identical in functionality to
  276        * {@link #containsValue containsValue}, (which is part of the
  277        * {@link Map} interface in the collections framework).
  278        *
  279        * @param      value   a value to search for
  280        * @return     <code>true</code> if and only if some key maps to the
  281        *             <code>value</code> argument in this hashtable as
  282        *             determined by the <tt>equals</tt> method;
  283        *             <code>false</code> otherwise.
  284        * @exception  NullPointerException  if the value is <code>null</code>
  285        */
  286       public synchronized boolean contains(Object value) {
  287           if (value == null) {
  288               throw new NullPointerException();
  289           }
  290   
  291           Entry tab[] = table;
  292           for (int i = tab.length ; i-- > 0 ;) {
  293               for (Entry<K,V> e = tab[i] ; e != null ; e = e.next) {
  294                   if (e.value.equals(value)) {
  295                       return true;
  296                   }
  297               }
  298           }
  299           return false;
  300       }
  301   
  302       /**
  303        * Returns true if this hashtable maps one or more keys to this value.
  304        *
  305        * <p>Note that this method is identical in functionality to {@link
  306        * #contains contains} (which predates the {@link Map} interface).
  307        *
  308        * @param value value whose presence in this hashtable is to be tested
  309        * @return <tt>true</tt> if this map maps one or more keys to the
  310        *         specified value
  311        * @throws NullPointerException  if the value is <code>null</code>
  312        * @since 1.2
  313        */
  314       public boolean containsValue(Object value) {
  315           return contains(value);
  316       }
  317   
  318       /**
  319        * Tests if the specified object is a key in this hashtable.
  320        *
  321        * @param   key   possible key
  322        * @return  <code>true</code> if and only if the specified object
  323        *          is a key in this hashtable, as determined by the
  324        *          <tt>equals</tt> method; <code>false</code> otherwise.
  325        * @throws  NullPointerException  if the key is <code>null</code>
  326        * @see     #contains(Object)
  327        */
  328       public synchronized boolean containsKey(Object key) {
  329           Entry tab[] = table;
  330           int hash = key.hashCode();
  331           int index = (hash & 0x7FFFFFFF) % tab.length;
  332           for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
  333               if ((e.hash == hash) && e.key.equals(key)) {
  334                   return true;
  335               }
  336           }
  337           return false;
  338       }
  339   
  340       /**
  341        * Returns the value to which the specified key is mapped,
  342        * or {@code null} if this map contains no mapping for the key.
  343        *
  344        * <p>More formally, if this map contains a mapping from a key
  345        * {@code k} to a value {@code v} such that {@code (key.equals(k))},
  346        * then this method returns {@code v}; otherwise it returns
  347        * {@code null}.  (There can be at most one such mapping.)
  348        *
  349        * @param key the key whose associated value is to be returned
  350        * @return the value to which the specified key is mapped, or
  351        *         {@code null} if this map contains no mapping for the key
  352        * @throws NullPointerException if the specified key is null
  353        * @see     #put(Object, Object)
  354        */
  355       public synchronized V get(Object key) {
  356           Entry tab[] = table;
  357           int hash = key.hashCode();
  358           int index = (hash & 0x7FFFFFFF) % tab.length;
  359           for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
  360               if ((e.hash == hash) && e.key.equals(key)) {
  361                   return e.value;
  362               }
  363           }
  364           return null;
  365       }
  366   
  367       /**
  368        * Increases the capacity of and internally reorganizes this
  369        * hashtable, in order to accommodate and access its entries more
  370        * efficiently.  This method is called automatically when the
  371        * number of keys in the hashtable exceeds this hashtable's capacity
  372        * and load factor.
  373        */
  374       protected void rehash() {
  375           int oldCapacity = table.length;
  376           Entry[] oldMap = table;
  377   
  378           int newCapacity = oldCapacity * 2 + 1;
  379           Entry[] newMap = new Entry[newCapacity];
  380   
  381           modCount++;
  382           threshold = (int)(newCapacity * loadFactor);
  383           table = newMap;
  384   
  385           for (int i = oldCapacity ; i-- > 0 ;) {
  386               for (Entry<K,V> old = oldMap[i] ; old != null ; ) {
  387                   Entry<K,V> e = old;
  388                   old = old.next;
  389   
  390                   int index = (e.hash & 0x7FFFFFFF) % newCapacity;
  391                   e.next = newMap[index];
  392                   newMap[index] = e;
  393               }
  394           }
  395       }
  396   
  397       /**
  398        * Maps the specified <code>key</code> to the specified
  399        * <code>value</code> in this hashtable. Neither the key nor the
  400        * value can be <code>null</code>. <p>
  401        *
  402        * The value can be retrieved by calling the <code>get</code> method
  403        * with a key that is equal to the original key.
  404        *
  405        * @param      key     the hashtable key
  406        * @param      value   the value
  407        * @return     the previous value of the specified key in this hashtable,
  408        *             or <code>null</code> if it did not have one
  409        * @exception  NullPointerException  if the key or value is
  410        *               <code>null</code>
  411        * @see     Object#equals(Object)
  412        * @see     #get(Object)
  413        */
  414       public synchronized V put(K key, V value) {
  415           // Make sure the value is not null
  416           if (value == null) {
  417               throw new NullPointerException();
  418           }
  419   
  420           // Makes sure the key is not already in the hashtable.
  421           Entry tab[] = table;
  422           int hash = key.hashCode();
  423           int index = (hash & 0x7FFFFFFF) % tab.length;
  424           for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
  425               if ((e.hash == hash) && e.key.equals(key)) {
  426                   V old = e.value;
  427                   e.value = value;
  428                   return old;
  429               }
  430           }
  431   
  432           modCount++;
  433           if (count >= threshold) {
  434               // Rehash the table if the threshold is exceeded
  435               rehash();
  436   
  437               tab = table;
  438               index = (hash & 0x7FFFFFFF) % tab.length;
  439           }
  440   
  441           // Creates the new entry.
  442           Entry<K,V> e = tab[index];
  443           tab[index] = new Entry<K,V>(hash, key, value, e);
  444           count++;
  445           return null;
  446       }
  447   
  448       /**
  449        * Removes the key (and its corresponding value) from this
  450        * hashtable. This method does nothing if the key is not in the hashtable.
  451        *
  452        * @param   key   the key that needs to be removed
  453        * @return  the value to which the key had been mapped in this hashtable,
  454        *          or <code>null</code> if the key did not have a mapping
  455        * @throws  NullPointerException  if the key is <code>null</code>
  456        */
  457       public synchronized V remove(Object key) {
  458           Entry tab[] = table;
  459           int hash = key.hashCode();
  460           int index = (hash & 0x7FFFFFFF) % tab.length;
  461           for (Entry<K,V> e = tab[index], prev = null ; e != null ; prev = e, e = e.next) {
  462               if ((e.hash == hash) && e.key.equals(key)) {
  463                   modCount++;
  464                   if (prev != null) {
  465                       prev.next = e.next;
  466                   } else {
  467                       tab[index] = e.next;
  468                   }
  469                   count--;
  470                   V oldValue = e.value;
  471                   e.value = null;
  472                   return oldValue;
  473               }
  474           }
  475           return null;
  476       }
  477   
  478       /**
  479        * Copies all of the mappings from the specified map to this hashtable.
  480        * These mappings will replace any mappings that this hashtable had for any
  481        * of the keys currently in the specified map.
  482        *
  483        * @param t mappings to be stored in this map
  484        * @throws NullPointerException if the specified map is null
  485        * @since 1.2
  486        */
  487       public synchronized void putAll(Map<? extends K, ? extends V> t) {
  488           for (Map.Entry<? extends K, ? extends V> e : t.entrySet())
  489               put(e.getKey(), e.getValue());
  490       }
  491   
  492       /**
  493        * Clears this hashtable so that it contains no keys.
  494        */
  495       public synchronized void clear() {
  496           Entry tab[] = table;
  497           modCount++;
  498           for (int index = tab.length; --index >= 0; )
  499               tab[index] = null;
  500           count = 0;
  501       }
  502   
  503       /**
  504        * Creates a shallow copy of this hashtable. All the structure of the
  505        * hashtable itself is copied, but the keys and values are not cloned.
  506        * This is a relatively expensive operation.
  507        *
  508        * @return  a clone of the hashtable
  509        */
  510       public synchronized Object clone() {
  511           try {
  512               Hashtable<K,V> t = (Hashtable<K,V>) super.clone();
  513               t.table = new Entry[table.length];
  514               for (int i = table.length ; i-- > 0 ; ) {
  515                   t.table[i] = (table[i] != null)
  516                       ? (Entry<K,V>) table[i].clone() : null;
  517               }
  518               t.keySet = null;
  519               t.entrySet = null;
  520               t.values = null;
  521               t.modCount = 0;
  522               return t;
  523           } catch (CloneNotSupportedException e) {
  524               // this shouldn't happen, since we are Cloneable
  525               throw new InternalError();
  526           }
  527       }
  528   
  529       /**
  530        * Returns a string representation of this <tt>Hashtable</tt> object
  531        * in the form of a set of entries, enclosed in braces and separated
  532        * by the ASCII characters "<tt>,&nbsp;</tt>" (comma and space). Each
  533        * entry is rendered as the key, an equals sign <tt>=</tt>, and the
  534        * associated element, where the <tt>toString</tt> method is used to
  535        * convert the key and element to strings.
  536        *
  537        * @return  a string representation of this hashtable
  538        */
  539       public synchronized String toString() {
  540           int max = size() - 1;
  541           if (max == -1)
  542               return "{}";
  543   
  544           StringBuilder sb = new StringBuilder();
  545           Iterator<Map.Entry<K,V>> it = entrySet().iterator();
  546   
  547           sb.append('{');
  548           for (int i = 0; ; i++) {
  549               Map.Entry<K,V> e = it.next();
  550               K key = e.getKey();
  551               V value = e.getValue();
  552               sb.append(key   == this ? "(this Map)" : key.toString());
  553               sb.append('=');
  554               sb.append(value == this ? "(this Map)" : value.toString());
  555   
  556               if (i == max)
  557                   return sb.append('}').toString();
  558               sb.append(", ");
  559           }
  560       }
  561   
  562   
  563       private <T> Enumeration<T> getEnumeration(int type) {
  564           if (count == 0) {
  565               return Collections.emptyEnumeration();
  566           } else {
  567               return new Enumerator<T>(type, false);
  568           }
  569       }
  570   
  571       private <T> Iterator<T> getIterator(int type) {
  572           if (count == 0) {
  573               return Collections.emptyIterator();
  574           } else {
  575               return new Enumerator<T>(type, true);
  576           }
  577       }
  578   
  579       // Views
  580   
  581       /**
  582        * Each of these fields are initialized to contain an instance of the
  583        * appropriate view the first time this view is requested.  The views are
  584        * stateless, so there's no reason to create more than one of each.
  585        */
  586       private transient volatile Set<K> keySet = null;
  587       private transient volatile Set<Map.Entry<K,V>> entrySet = null;
  588       private transient volatile Collection<V> values = null;
  589   
  590       /**
  591        * Returns a {@link Set} view of the keys contained in this map.
  592        * The set is backed by the map, so changes to the map are
  593        * reflected in the set, and vice-versa.  If the map is modified
  594        * while an iteration over the set is in progress (except through
  595        * the iterator's own <tt>remove</tt> operation), the results of
  596        * the iteration are undefined.  The set supports element removal,
  597        * which removes the corresponding mapping from the map, via the
  598        * <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
  599        * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>
  600        * operations.  It does not support the <tt>add</tt> or <tt>addAll</tt>
  601        * operations.
  602        *
  603        * @since 1.2
  604        */
  605       public Set<K> keySet() {
  606           if (keySet == null)
  607               keySet = Collections.synchronizedSet(new KeySet(), this);
  608           return keySet;
  609       }
  610   
  611       private class KeySet extends AbstractSet<K> {
  612           public Iterator<K> iterator() {
  613               return getIterator(KEYS);
  614           }
  615           public int size() {
  616               return count;
  617           }
  618           public boolean contains(Object o) {
  619               return containsKey(o);
  620           }
  621           public boolean remove(Object o) {
  622               return Hashtable.this.remove(o) != null;
  623           }
  624           public void clear() {
  625               Hashtable.this.clear();
  626           }
  627       }
  628   
  629       /**
  630        * Returns a {@link Set} view of the mappings contained in this map.
  631        * The set is backed by the map, so changes to the map are
  632        * reflected in the set, and vice-versa.  If the map is modified
  633        * while an iteration over the set is in progress (except through
  634        * the iterator's own <tt>remove</tt> operation, or through the
  635        * <tt>setValue</tt> operation on a map entry returned by the
  636        * iterator) the results of the iteration are undefined.  The set
  637        * supports element removal, which removes the corresponding
  638        * mapping from the map, via the <tt>Iterator.remove</tt>,
  639        * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt> and
  640        * <tt>clear</tt> operations.  It does not support the
  641        * <tt>add</tt> or <tt>addAll</tt> operations.
  642        *
  643        * @since 1.2
  644        */
  645       public Set<Map.Entry<K,V>> entrySet() {
  646           if (entrySet==null)
  647               entrySet = Collections.synchronizedSet(new EntrySet(), this);
  648           return entrySet;
  649       }
  650   
  651       private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
  652           public Iterator<Map.Entry<K,V>> iterator() {
  653               return getIterator(ENTRIES);
  654           }
  655   
  656           public boolean add(Map.Entry<K,V> o) {
  657               return super.add(o);
  658           }
  659   
  660           public boolean contains(Object o) {
  661               if (!(o instanceof Map.Entry))
  662                   return false;
  663               Map.Entry entry = (Map.Entry)o;
  664               Object key = entry.getKey();
  665               Entry[] tab = table;
  666               int hash = key.hashCode();
  667               int index = (hash & 0x7FFFFFFF) % tab.length;
  668   
  669               for (Entry e = tab[index]; e != null; e = e.next)
  670                   if (e.hash==hash && e.equals(entry))
  671                       return true;
  672               return false;
  673           }
  674   
  675           public boolean remove(Object o) {
  676               if (!(o instanceof Map.Entry))
  677                   return false;
  678               Map.Entry<K,V> entry = (Map.Entry<K,V>) o;
  679               K key = entry.getKey();
  680               Entry[] tab = table;
  681               int hash = key.hashCode();
  682               int index = (hash & 0x7FFFFFFF) % tab.length;
  683   
  684               for (Entry<K,V> e = tab[index], prev = null; e != null;
  685                    prev = e, e = e.next) {
  686                   if (e.hash==hash && e.equals(entry)) {
  687                       modCount++;
  688                       if (prev != null)
  689                           prev.next = e.next;
  690                       else
  691                           tab[index] = e.next;
  692   
  693                       count--;
  694                       e.value = null;
  695                       return true;
  696                   }
  697               }
  698               return false;
  699           }
  700   
  701           public int size() {
  702               return count;
  703           }
  704   
  705           public void clear() {
  706               Hashtable.this.clear();
  707           }
  708       }
  709   
  710       /**
  711        * Returns a {@link Collection} view of the values contained in this map.
  712        * The collection is backed by the map, so changes to the map are
  713        * reflected in the collection, and vice-versa.  If the map is
  714        * modified while an iteration over the collection is in progress
  715        * (except through the iterator's own <tt>remove</tt> operation),
  716        * the results of the iteration are undefined.  The collection
  717        * supports element removal, which removes the corresponding
  718        * mapping from the map, via the <tt>Iterator.remove</tt>,
  719        * <tt>Collection.remove</tt>, <tt>removeAll</tt>,
  720        * <tt>retainAll</tt> and <tt>clear</tt> operations.  It does not
  721        * support the <tt>add</tt> or <tt>addAll</tt> operations.
  722        *
  723        * @since 1.2
  724        */
  725       public Collection<V> values() {
  726           if (values==null)
  727               values = Collections.synchronizedCollection(new ValueCollection(),
  728                                                           this);
  729           return values;
  730       }
  731   
  732       private class ValueCollection extends AbstractCollection<V> {
  733           public Iterator<V> iterator() {
  734               return getIterator(VALUES);
  735           }
  736           public int size() {
  737               return count;
  738           }
  739           public boolean contains(Object o) {
  740               return containsValue(o);
  741           }
  742           public void clear() {
  743               Hashtable.this.clear();
  744           }
  745       }
  746   
  747       // Comparison and hashing
  748   
  749       /**
  750        * Compares the specified Object with this Map for equality,
  751        * as per the definition in the Map interface.
  752        *
  753        * @param  o object to be compared for equality with this hashtable
  754        * @return true if the specified Object is equal to this Map
  755        * @see Map#equals(Object)
  756        * @since 1.2
  757        */
  758       public synchronized boolean equals(Object o) {
  759           if (o == this)
  760               return true;
  761   
  762           if (!(o instanceof Map))
  763               return false;
  764           Map<K,V> t = (Map<K,V>) o;
  765           if (t.size() != size())
  766               return false;
  767   
  768           try {
  769               Iterator<Map.Entry<K,V>> i = entrySet().iterator();
  770               while (i.hasNext()) {
  771                   Map.Entry<K,V> e = i.next();
  772                   K key = e.getKey();
  773                   V value = e.getValue();
  774                   if (value == null) {
  775                       if (!(t.get(key)==null && t.containsKey(key)))
  776                           return false;
  777                   } else {
  778                       if (!value.equals(t.get(key)))
  779                           return false;
  780                   }
  781               }
  782           } catch (ClassCastException unused)   {
  783               return false;
  784           } catch (NullPointerException unused) {
  785               return false;
  786           }
  787   
  788           return true;
  789       }
  790   
  791       /**
  792        * Returns the hash code value for this Map as per the definition in the
  793        * Map interface.
  794        *
  795        * @see Map#hashCode()
  796        * @since 1.2
  797        */
  798       public synchronized int hashCode() {
  799           /*
  800            * This code detects the recursion caused by computing the hash code
  801            * of a self-referential hash table and prevents the stack overflow
  802            * that would otherwise result.  This allows certain 1.1-era
  803            * applets with self-referential hash tables to work.  This code
  804            * abuses the loadFactor field to do double-duty as a hashCode
  805            * in progress flag, so as not to worsen the space performance.
  806            * A negative load factor indicates that hash code computation is
  807            * in progress.
  808            */
  809           int h = 0;
  810           if (count == 0 || loadFactor < 0)
  811               return h;  // Returns zero
  812   
  813           loadFactor = -loadFactor;  // Mark hashCode computation in progress
  814           Entry[] tab = table;
  815           for (int i = 0; i < tab.length; i++)
  816               for (Entry e = tab[i]; e != null; e = e.next)
  817                   h += e.key.hashCode() ^ e.value.hashCode();
  818           loadFactor = -loadFactor;  // Mark hashCode computation complete
  819   
  820           return h;
  821       }
  822   
  823       /**
  824        * Save the state of the Hashtable to a stream (i.e., serialize it).
  825        *
  826        * @serialData The <i>capacity</i> of the Hashtable (the length of the
  827        *             bucket array) is emitted (int), followed by the
  828        *             <i>size</i> of the Hashtable (the number of key-value
  829        *             mappings), followed by the key (Object) and value (Object)
  830        *             for each key-value mapping represented by the Hashtable
  831        *             The key-value mappings are emitted in no particular order.
  832        */
  833       private synchronized void writeObject(java.io.ObjectOutputStream s)
  834           throws IOException
  835       {
  836           // Write out the length, threshold, loadfactor
  837           s.defaultWriteObject();
  838   
  839           // Write out length, count of elements and then the key/value objects
  840           s.writeInt(table.length);
  841           s.writeInt(count);
  842           for (int index = table.length-1; index >= 0; index--) {
  843               Entry entry = table[index];
  844   
  845               while (entry != null) {
  846                   s.writeObject(entry.key);
  847                   s.writeObject(entry.value);
  848                   entry = entry.next;
  849               }
  850           }
  851       }
  852   
  853       /**
  854        * Reconstitute the Hashtable from a stream (i.e., deserialize it).
  855        */
  856       private void readObject(java.io.ObjectInputStream s)
  857            throws IOException, ClassNotFoundException
  858       {
  859           // Read in the length, threshold, and loadfactor
  860           s.defaultReadObject();
  861   
  862           // Read the original length of the array and number of elements
  863           int origlength = s.readInt();
  864           int elements = s.readInt();
  865   
  866           // Compute new size with a bit of room 5% to grow but
  867           // no larger than the original size.  Make the length
  868           // odd if it's large enough, this helps distribute the entries.
  869           // Guard against the length ending up zero, that's not valid.
  870           int length = (int)(elements * loadFactor) + (elements / 20) + 3;
  871           if (length > elements && (length & 1) == 0)
  872               length--;
  873           if (origlength > 0 && length > origlength)
  874               length = origlength;
  875   
  876           Entry[] table = new Entry[length];
  877           count = 0;
  878   
  879           // Read the number of elements and then all the key/value objects
  880           for (; elements > 0; elements--) {
  881               K key = (K)s.readObject();
  882               V value = (V)s.readObject();
  883               // synch could be eliminated for performance
  884               reconstitutionPut(table, key, value);
  885           }
  886           this.table = table;
  887       }
  888   
  889       /**
  890        * The put method used by readObject. This is provided because put
  891        * is overridable and should not be called in readObject since the
  892        * subclass will not yet be initialized.
  893        *
  894        * <p>This differs from the regular put method in several ways. No
  895        * checking for rehashing is necessary since the number of elements
  896        * initially in the table is known. The modCount is not incremented
  897        * because we are creating a new instance. Also, no return value
  898        * is needed.
  899        */
  900       private void reconstitutionPut(Entry[] tab, K key, V value)
  901           throws StreamCorruptedException
  902       {
  903           if (value == null) {
  904               throw new java.io.StreamCorruptedException();
  905           }
  906           // Makes sure the key is not already in the hashtable.
  907           // This should not happen in deserialized version.
  908           int hash = key.hashCode();
  909           int index = (hash & 0x7FFFFFFF) % tab.length;
  910           for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
  911               if ((e.hash == hash) && e.key.equals(key)) {
  912                   throw new java.io.StreamCorruptedException();
  913               }
  914           }
  915           // Creates the new entry.
  916           Entry<K,V> e = tab[index];
  917           tab[index] = new Entry<K,V>(hash, key, value, e);
  918           count++;
  919       }
  920   
  921       /**
  922        * Hashtable collision list.
  923        */
  924       private static class Entry<K,V> implements Map.Entry<K,V> {
  925           int hash;
  926           K key;
  927           V value;
  928           Entry<K,V> next;
  929   
  930           protected Entry(int hash, K key, V value, Entry<K,V> next) {
  931               this.hash = hash;
  932               this.key = key;
  933               this.value = value;
  934               this.next = next;
  935           }
  936   
  937           protected Object clone() {
  938               return new Entry<K,V>(hash, key, value,
  939                                     (next==null ? null : (Entry<K,V>) next.clone()));
  940           }
  941   
  942           // Map.Entry Ops
  943   
  944           public K getKey() {
  945               return key;
  946           }
  947   
  948           public V getValue() {
  949               return value;
  950           }
  951   
  952           public V setValue(V value) {
  953               if (value == null)
  954                   throw new NullPointerException();
  955   
  956               V oldValue = this.value;
  957               this.value = value;
  958               return oldValue;
  959           }
  960   
  961           public boolean equals(Object o) {
  962               if (!(o instanceof Map.Entry))
  963                   return false;
  964               Map.Entry e = (Map.Entry)o;
  965   
  966               return (key==null ? e.getKey()==null : key.equals(e.getKey())) &&
  967                  (value==null ? e.getValue()==null : value.equals(e.getValue()));
  968           }
  969   
  970           public int hashCode() {
  971               return hash ^ (value==null ? 0 : value.hashCode());
  972           }
  973   
  974           public String toString() {
  975               return key.toString()+"="+value.toString();
  976           }
  977       }
  978   
  979       // Types of Enumerations/Iterations
  980       private static final int KEYS = 0;
  981       private static final int VALUES = 1;
  982       private static final int ENTRIES = 2;
  983   
  984       /**
  985        * A hashtable enumerator class.  This class implements both the
  986        * Enumeration and Iterator interfaces, but individual instances
  987        * can be created with the Iterator methods disabled.  This is necessary
  988        * to avoid unintentionally increasing the capabilities granted a user
  989        * by passing an Enumeration.
  990        */
  991       private class Enumerator<T> implements Enumeration<T>, Iterator<T> {
  992           Entry[] table = Hashtable.this.table;
  993           int index = table.length;
  994           Entry<K,V> entry = null;
  995           Entry<K,V> lastReturned = null;
  996           int type;
  997   
  998           /**
  999            * Indicates whether this Enumerator is serving as an Iterator
 1000            * or an Enumeration.  (true -> Iterator).
 1001            */
 1002           boolean iterator;
 1003   
 1004           /**
 1005            * The modCount value that the iterator believes that the backing
 1006            * Hashtable should have.  If this expectation is violated, the iterator
 1007            * has detected concurrent modification.
 1008            */
 1009           protected int expectedModCount = modCount;
 1010   
 1011           Enumerator(int type, boolean iterator) {
 1012               this.type = type;
 1013               this.iterator = iterator;
 1014           }
 1015   
 1016           public boolean hasMoreElements() {
 1017               Entry<K,V> e = entry;
 1018               int i = index;
 1019               Entry[] t = table;
 1020               /* Use locals for faster loop iteration */
 1021               while (e == null && i > 0) {
 1022                   e = t[--i];
 1023               }
 1024               entry = e;
 1025               index = i;
 1026               return e != null;
 1027           }
 1028   
 1029           public T nextElement() {
 1030               Entry<K,V> et = entry;
 1031               int i = index;
 1032               Entry[] t = table;
 1033               /* Use locals for faster loop iteration */
 1034               while (et == null && i > 0) {
 1035                   et = t[--i];
 1036               }
 1037               entry = et;
 1038               index = i;
 1039               if (et != null) {
 1040                   Entry<K,V> e = lastReturned = entry;
 1041                   entry = e.next;
 1042                   return type == KEYS ? (T)e.key : (type == VALUES ? (T)e.value : (T)e);
 1043               }
 1044               throw new NoSuchElementException("Hashtable Enumerator");
 1045           }
 1046   
 1047           // Iterator methods
 1048           public boolean hasNext() {
 1049               return hasMoreElements();
 1050           }
 1051   
 1052           public T next() {
 1053               if (modCount != expectedModCount)
 1054                   throw new ConcurrentModificationException();
 1055               return nextElement();
 1056           }
 1057   
 1058           public void remove() {
 1059               if (!iterator)
 1060                   throw new UnsupportedOperationException();
 1061               if (lastReturned == null)
 1062                   throw new IllegalStateException("Hashtable Enumerator");
 1063               if (modCount != expectedModCount)
 1064                   throw new ConcurrentModificationException();
 1065   
 1066               synchronized(Hashtable.this) {
 1067                   Entry[] tab = Hashtable.this.table;
 1068                   int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length;
 1069   
 1070                   for (Entry<K,V> e = tab[index], prev = null; e != null;
 1071                        prev = e, e = e.next) {
 1072                       if (e == lastReturned) {
 1073                           modCount++;
 1074                           expectedModCount++;
 1075                           if (prev == null)
 1076                               tab[index] = e.next;
 1077                           else
 1078                               prev.next = e.next;
 1079                           count--;
 1080                           lastReturned = null;
 1081                           return;
 1082                       }
 1083                   }
 1084                   throw new ConcurrentModificationException();
 1085               }
 1086           }
 1087       }
 1088   }

Save This Page
Home » openjdk-7 » java » util » [javadoc | source]