<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Java Hashtable的實現


      先附源碼:

      package java.util;
      import java.io.*;
      
      /**
       * This class implements a hash table, which maps keys to values. Any
       * non-<code>null</code> object can be used as a key or as a value. <p>
       *
       * To successfully store and retrieve objects from a hashtable, the
       * objects used as keys must implement the <code>hashCode</code>
       * method and the <code>equals</code> method. <p>
       *
       * An instance of <code>Hashtable</code> has two parameters that affect its
       * performance: <i>initial capacity</i> and <i>load factor</i>.  The
       * <i>capacity</i> is the number of <i>buckets</i> in the hash table, and the
       * <i>initial capacity</i> is simply the capacity at the time the hash table
       * is created.  Note that the hash table is <i>open</i>: in the case of a "hash
       * collision", a single bucket stores multiple entries, which must be searched
       * sequentially.  The <i>load factor</i> is a measure of how full the hash
       * table is allowed to get before its capacity is automatically increased.
       * The initial capacity and load factor parameters are merely hints to
       * the implementation.  The exact details as to when and whether the rehash
       * method is invoked are implementation-dependent.<p>
       *
       * Generally, the default load factor (.75) offers a good tradeoff between
       * time and space costs.  Higher values decrease the space overhead but
       * increase the time cost to look up an entry (which is reflected in most
       * <tt>Hashtable</tt> operations, including <tt>get</tt> and <tt>put</tt>).<p>
       *
       * The initial capacity controls a tradeoff between wasted space and the
       * need for <code>rehash</code> operations, which are time-consuming.
       * No <code>rehash</code> operations will <i>ever</i> occur if the initial
       * capacity is greater than the maximum number of entries the
       * <tt>Hashtable</tt> will contain divided by its load factor.  However,
       * setting the initial capacity too high can waste space.<p>
       *
       * If many entries are to be made into a <code>Hashtable</code>,
       * creating it with a sufficiently large capacity may allow the
       * entries to be inserted more efficiently than letting it perform
       * automatic rehashing as needed to grow the table. <p>
       *
       * This example creates a hashtable of numbers. It uses the names of
       * the numbers as keys:
       * <pre>   {@code
       *   Hashtable<String, Integer> numbers
       *     = new Hashtable<String, Integer>();
       *   numbers.put("one", 1);
       *   numbers.put("two", 2);
       *   numbers.put("three", 3);}</pre>
       *
       * <p>To retrieve a number, use the following code:
       * <pre>   {@code
       *   Integer n = numbers.get("two");
       *   if (n != null) {
       *     System.out.println("two = " + n);
       *   }}</pre>
       *
       * <p>The iterators returned by the <tt>iterator</tt> method of the collections
       * returned by all of this class's "collection view methods" are
       * <em>fail-fast</em>: if the Hashtable is structurally modified at any time
       * after the iterator is created, in any way except through the iterator's own
       * <tt>remove</tt> method, the iterator will throw a {@link
       * 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.
       * The Enumerations returned by Hashtable's keys and elements methods are
       * <em>not</em> fail-fast.
       *
       * <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 <tt>ConcurrentModificationException</tt> on a best-effort basis.
       * Therefore, it would be wrong to write a program that depended on this
       * exception for its correctness: <i>the fail-fast behavior of iterators
       * should be used only to detect bugs.</i>
       *
       * <p>As of the Java 2 platform v1.2, this class was retrofitted to
       * implement the {@link Map} interface, making it a member of the
       * <a href="{@docRoot}/../technotes/guides/collections/index.html">
       *
       * Java Collections Framework</a>.  Unlike the new collection
       * implementations, {@code Hashtable} is synchronized.  If a
       * thread-safe implementation is not needed, it is recommended to use
       * {@link HashMap} in place of {@code Hashtable}.  If a thread-safe
       * highly-concurrent implementation is desired, then it is recommended
       * to use {@link java.util.concurrent.ConcurrentHashMap} in place of
       * {@code Hashtable}.
       *
       * @author  Arthur van Hoff
       * @author  Josh Bloch
       * @author  Neal Gafter
       * @see     Object#equals(java.lang.Object)
       * @see     Object#hashCode()
       * @see     Hashtable#rehash()
       * @see     Collection
       * @see     Map
       * @see     HashMap
       * @see     TreeMap
       * @since JDK1.0
       */
      public class Hashtable<K,V>
          extends Dictionary<K,V>
          implements Map<K,V>, Cloneable, java.io.Serializable {
      
          /**
           * The hash table data.
           */
          private transient Entry<K,V>[] table;
      
          /**
           * The total number of entries in the hash table.
           */
          private transient int count;
      
          /**
           * The table is rehashed when its size exceeds this threshold.  (The
           * value of this field is (int)(capacity * loadFactor).)
           *
           * @serial
           */
          private int threshold;
      
          /**
           * The load factor for the hashtable.
           *
           * @serial
           */
          private float loadFactor;
      
          /**
           * The number of times this Hashtable has been structurally modified
           * Structural modifications are those that change the number of entries in
           * the Hashtable or otherwise modify its internal structure (e.g.,
           * rehash).  This field is used to make iterators on Collection-views of
           * the Hashtable fail-fast.  (See ConcurrentModificationException).
           */
          private transient int modCount = 0;
      
          /** use serialVersionUID from JDK 1.0.2 for interoperability */
          private static final long serialVersionUID = 1421746759512286392L;
      
          /**
           * The default threshold of map capacity above which alternative hashing is
           * used for String keys. Alternative hashing reduces the incidence of
           * collisions due to weak hash code calculation for String keys.
           * <p>
           * This value may be overridden by defining the system property
           * {@code jdk.map.althashing.threshold}. A property value of {@code 1}
           * forces alternative hashing to be used at all times whereas
           * {@code -1} value ensures that alternative hashing is never used.
           */
          static final int ALTERNATIVE_HASHING_THRESHOLD_DEFAULT = Integer.MAX_VALUE;
      
          /**
           * holds values which can't be initialized until after VM is booted.
           */
          private static class Holder {
      
              /**
               * Table capacity above which to switch to use alternative hashing.
               */
              static final int ALTERNATIVE_HASHING_THRESHOLD;
      
              static {
                  String altThreshold = java.security.AccessController.doPrivileged(
                      new sun.security.action.GetPropertyAction(
                          "jdk.map.althashing.threshold"));
      
                  int threshold;
                  try {
                      threshold = (null != altThreshold)
                              ? Integer.parseInt(altThreshold)
                              : ALTERNATIVE_HASHING_THRESHOLD_DEFAULT;
      
                      // disable alternative hashing if -1
                      if (threshold == -1) {
                          threshold = Integer.MAX_VALUE;
                      }
      
                      if (threshold < 0) {
                          throw new IllegalArgumentException("value must be positive integer.");
                      }
                  } catch(IllegalArgumentException failed) {
                      throw new Error("Illegal value for 'jdk.map.althashing.threshold'", failed);
                  }
      
                  ALTERNATIVE_HASHING_THRESHOLD = threshold;
              }
          }
      
          /**
           * A randomizing value associated with this instance that is applied to
           * hash code of keys to make hash collisions harder to find.
           */
          transient int hashSeed;
      
          /**
           * Initialize the hashing mask value.
           */
          final boolean initHashSeedAsNeeded(int capacity) {
              boolean currentAltHashing = hashSeed != 0;
              boolean useAltHashing = sun.misc.VM.isBooted() &&
                      (capacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD);
              boolean switching = currentAltHashing ^ useAltHashing;
              if (switching) {
                  hashSeed = useAltHashing
                      ? sun.misc.Hashing.randomHashSeed(this)
                      : 0;
              }
              return switching;
          }
      
          private int hash(Object k) {
              // hashSeed will be zero if alternative hashing is disabled.
              return hashSeed ^ k.hashCode();
          }
      
          /**
           * Constructs a new, empty hashtable with the specified initial
           * capacity and the specified load factor.
           *
           * @param      initialCapacity   the initial capacity of the hashtable.
           * @param      loadFactor        the load factor of the hashtable.
           * @exception  IllegalArgumentException  if the initial capacity is less
           *             than zero, or if the load factor is nonpositive.
           */
          public Hashtable(int initialCapacity, float loadFactor) {
              if (initialCapacity < 0)
                  throw new IllegalArgumentException("Illegal Capacity: "+
                                                     initialCapacity);
              if (loadFactor <= 0 || Float.isNaN(loadFactor))
                  throw new IllegalArgumentException("Illegal Load: "+loadFactor);
      
              if (initialCapacity==0)
                  initialCapacity = 1;
              this.loadFactor = loadFactor;
              table = new Entry[initialCapacity];
              threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
              initHashSeedAsNeeded(initialCapacity);
          }
      
          /**
           * Constructs a new, empty hashtable with the specified initial capacity
           * and default load factor (0.75).
           *
           * @param     initialCapacity   the initial capacity of the hashtable.
           * @exception IllegalArgumentException if the initial capacity is less
           *              than zero.
           */
          public Hashtable(int initialCapacity) {
              this(initialCapacity, 0.75f);
          }
      
          /**
           * Constructs a new, empty hashtable with a default initial capacity (11)
           * and load factor (0.75).
           */
          public Hashtable() {
              this(11, 0.75f);
          }
      
          /**
           * Constructs a new hashtable with the same mappings as the given
           * Map.  The hashtable is created with an initial capacity sufficient to
           * hold the mappings in the given Map and a default load factor (0.75).
           *
           * @param t the map whose mappings are to be placed in this map.
           * @throws NullPointerException if the specified map is null.
           * @since   1.2
           */
          public Hashtable(Map<? extends K, ? extends V> t) {
              this(Math.max(2*t.size(), 11), 0.75f);
              putAll(t);
          }
      
          /**
           * Returns the number of keys in this hashtable.
           *
           * @return  the number of keys in this hashtable.
           */
          public synchronized int size() {
              return count;
          }
      
          /**
           * Tests if this hashtable maps no keys to values.
           *
           * @return  <code>true</code> if this hashtable maps no keys to values;
           *          <code>false</code> otherwise.
           */
          public synchronized boolean isEmpty() {
              return count == 0;
          }
      
          /**
           * Returns an enumeration of the keys in this hashtable.
           *
           * @return  an enumeration of the keys in this hashtable.
           * @see     Enumeration
           * @see     #elements()
           * @see     #keySet()
           * @see     Map
           */
          public synchronized Enumeration<K> keys() {
              return this.<K>getEnumeration(KEYS);
          }
      
          /**
           * Returns an enumeration of the values in this hashtable.
           * Use the Enumeration methods on the returned object to fetch the elements
           * sequentially.
           *
           * @return  an enumeration of the values in this hashtable.
           * @see     java.util.Enumeration
           * @see     #keys()
           * @see     #values()
           * @see     Map
           */
          public synchronized Enumeration<V> elements() {
              return this.<V>getEnumeration(VALUES);
          }
      
          /**
           * Tests if some key maps into the specified value in this hashtable.
           * This operation is more expensive than the {@link #containsKey
           * containsKey} method.
           *
           * <p>Note that this method is identical in functionality to
           * {@link #containsValue containsValue}, (which is part of the
           * {@link Map} interface in the collections framework).
           *
           * @param      value   a value to search for
           * @return     <code>true</code> if and only if some key maps to the
           *             <code>value</code> argument in this hashtable as
           *             determined by the <tt>equals</tt> method;
           *             <code>false</code> otherwise.
           * @exception  NullPointerException  if the value is <code>null</code>
           */
          public synchronized boolean contains(Object value) {
              if (value == null) {
                  throw new NullPointerException();
              }
      
              Entry tab[] = table;
              for (int i = tab.length ; i-- > 0 ;) {
                  for (Entry<K,V> e = tab[i] ; e != null ; e = e.next) {
                      if (e.value.equals(value)) {
                          return true;
                      }
                  }
              }
              return false;
          }
      
          /**
           * Returns true if this hashtable maps one or more keys to this value.
           *
           * <p>Note that this method is identical in functionality to {@link
           * #contains contains} (which predates the {@link Map} interface).
           *
           * @param value value whose presence in this hashtable is to be tested
           * @return <tt>true</tt> if this map maps one or more keys to the
           *         specified value
           * @throws NullPointerException  if the value is <code>null</code>
           * @since 1.2
           */
          public boolean containsValue(Object value) {
              return contains(value);
          }
      
          /**
           * Tests if the specified object is a key in this hashtable.
           *
           * @param   key   possible key
           * @return  <code>true</code> if and only if the specified object
           *          is a key in this hashtable, as determined by the
           *          <tt>equals</tt> method; <code>false</code> otherwise.
           * @throws  NullPointerException  if the key is <code>null</code>
           * @see     #contains(Object)
           */
          public synchronized boolean containsKey(Object key) {
              Entry tab[] = table;
              int hash = hash(key);
              int index = (hash & 0x7FFFFFFF) % tab.length;
              for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
                  if ((e.hash == hash) && e.key.equals(key)) {
                      return true;
                  }
              }
              return false;
          }
      
          /**
           * Returns the value to which the specified key is mapped,
           * or {@code null} if this map contains no mapping for the key.
           *
           * <p>More formally, if this map contains a mapping from a key
           * {@code k} to a value {@code v} such that {@code (key.equals(k))},
           * then this method returns {@code v}; otherwise it returns
           * {@code null}.  (There can be at most one such mapping.)
           *
           * @param key the key whose associated value is to be returned
           * @return the value to which the specified key is mapped, or
           *         {@code null} if this map contains no mapping for the key
           * @throws NullPointerException if the specified key is null
           * @see     #put(Object, Object)
           */
          public synchronized V get(Object key) {
              Entry tab[] = table;
              int hash = hash(key);
              int index = (hash & 0x7FFFFFFF) % tab.length;
              for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
                  if ((e.hash == hash) && e.key.equals(key)) {
                      return e.value;
                  }
              }
              return null;
          }
      
          /**
           * The maximum size of array to allocate.
           * Some VMs reserve some header words in an array.
           * Attempts to allocate larger arrays may result in
           * OutOfMemoryError: Requested array size exceeds VM limit
           */
          private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
      
          /**
           * Increases the capacity of and internally reorganizes this
           * hashtable, in order to accommodate and access its entries more
           * efficiently.  This method is called automatically when the
           * number of keys in the hashtable exceeds this hashtable's capacity
           * and load factor.
           */
          protected void rehash() {
              int oldCapacity = table.length;
              Entry<K,V>[] oldMap = table;
      
              // overflow-conscious code
              int newCapacity = (oldCapacity << 1) + 1;
              if (newCapacity - MAX_ARRAY_SIZE > 0) {
                  if (oldCapacity == MAX_ARRAY_SIZE)
                      // Keep running with MAX_ARRAY_SIZE buckets
                      return;
                  newCapacity = MAX_ARRAY_SIZE;
              }
              Entry<K,V>[] newMap = new Entry[newCapacity];
      
              modCount++;
              threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
              boolean rehash = initHashSeedAsNeeded(newCapacity);
      
              table = newMap;
      
              for (int i = oldCapacity ; i-- > 0 ;) {
                  for (Entry<K,V> old = oldMap[i] ; old != null ; ) {
                      Entry<K,V> e = old;
                      old = old.next;
      
                      if (rehash) {
                          e.hash = hash(e.key);
                      }
                      int index = (e.hash & 0x7FFFFFFF) % newCapacity;
                      e.next = newMap[index];
                      newMap[index] = e;
                  }
              }
          }
      
          /**
           * Maps the specified <code>key</code> to the specified
           * <code>value</code> in this hashtable. Neither the key nor the
           * value can be <code>null</code>. <p>
           *
           * The value can be retrieved by calling the <code>get</code> method
           * with a key that is equal to the original key.
           *
           * @param      key     the hashtable key
           * @param      value   the value
           * @return     the previous value of the specified key in this hashtable,
           *             or <code>null</code> if it did not have one
           * @exception  NullPointerException  if the key or value is
           *               <code>null</code>
           * @see     Object#equals(Object)
           * @see     #get(Object)
           */
          public synchronized V put(K key, V value) {
              // Make sure the value is not null
              if (value == null) {
                  throw new NullPointerException();
              }
      
              // Makes sure the key is not already in the hashtable.
              Entry tab[] = table;
              int hash = hash(key);
              int index = (hash & 0x7FFFFFFF) % tab.length;
              for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
                  if ((e.hash == hash) && e.key.equals(key)) {
                      V old = e.value;
                      e.value = value;
                      return old;
                  }
              }
      
              modCount++;
              if (count >= threshold) {
                  // Rehash the table if the threshold is exceeded
                  rehash();
      
                  tab = table;
                  hash = hash(key);
                  index = (hash & 0x7FFFFFFF) % tab.length;
              }
      
              // Creates the new entry.
              Entry<K,V> e = tab[index];
              tab[index] = new Entry<>(hash, key, value, e);
              count++;
              return null;
          }
      
          /**
           * Removes the key (and its corresponding value) from this
           * hashtable. This method does nothing if the key is not in the hashtable.
           *
           * @param   key   the key that needs to be removed
           * @return  the value to which the key had been mapped in this hashtable,
           *          or <code>null</code> if the key did not have a mapping
           * @throws  NullPointerException  if the key is <code>null</code>
           */
          public synchronized V remove(Object key) {
              Entry tab[] = table;
              int hash = hash(key);
              int index = (hash & 0x7FFFFFFF) % tab.length;
              for (Entry<K,V> e = tab[index], prev = null ; e != null ; prev = e, e = e.next) {
                  if ((e.hash == hash) && e.key.equals(key)) {
                      modCount++;
                      if (prev != null) {
                          prev.next = e.next;
                      } else {
                          tab[index] = e.next;
                      }
                      count--;
                      V oldValue = e.value;
                      e.value = null;
                      return oldValue;
                  }
              }
              return null;
          }
      
          /**
           * Copies all of the mappings from the specified map to this hashtable.
           * These mappings will replace any mappings that this hashtable had for any
           * of the keys currently in the specified map.
           *
           * @param t mappings to be stored in this map
           * @throws NullPointerException if the specified map is null
           * @since 1.2
           */
          public synchronized void putAll(Map<? extends K, ? extends V> t) {
              for (Map.Entry<? extends K, ? extends V> e : t.entrySet())
                  put(e.getKey(), e.getValue());
          }
      
          /**
           * Clears this hashtable so that it contains no keys.
           */
          public synchronized void clear() {
              Entry tab[] = table;
              modCount++;
              for (int index = tab.length; --index >= 0; )
                  tab[index] = null;
              count = 0;
          }
      
          /**
           * Creates a shallow copy of this hashtable. All the structure of the
           * hashtable itself is copied, but the keys and values are not cloned.
           * This is a relatively expensive operation.
           *
           * @return  a clone of the hashtable
           */
          public synchronized Object clone() {
              try {
                  Hashtable<K,V> t = (Hashtable<K,V>) super.clone();
                  t.table = new Entry[table.length];
                  for (int i = table.length ; i-- > 0 ; ) {
                      t.table[i] = (table[i] != null)
                          ? (Entry<K,V>) table[i].clone() : null;
                  }
                  t.keySet = null;
                  t.entrySet = null;
                  t.values = null;
                  t.modCount = 0;
                  return t;
              } catch (CloneNotSupportedException e) {
                  // this shouldn't happen, since we are Cloneable
                  throw new InternalError();
              }
          }
      
          /**
           * Returns a string representation of this <tt>Hashtable</tt> object
           * in the form of a set of entries, enclosed in braces and separated
           * by the ASCII characters "<tt>, </tt>" (comma and space). Each
           * entry is rendered as the key, an equals sign <tt>=</tt>, and the
           * associated element, where the <tt>toString</tt> method is used to
           * convert the key and element to strings.
           *
           * @return  a string representation of this hashtable
           */
          public synchronized String toString() {
              int max = size() - 1;
              if (max == -1)
                  return "{}";
      
              StringBuilder sb = new StringBuilder();
              Iterator<Map.Entry<K,V>> it = entrySet().iterator();
      
              sb.append('{');
              for (int i = 0; ; i++) {
                  Map.Entry<K,V> e = it.next();
                  K key = e.getKey();
                  V value = e.getValue();
                  sb.append(key   == this ? "(this Map)" : key.toString());
                  sb.append('=');
                  sb.append(value == this ? "(this Map)" : value.toString());
      
                  if (i == max)
                      return sb.append('}').toString();
                  sb.append(", ");
              }
          }
      
      
          private <T> Enumeration<T> getEnumeration(int type) {
              if (count == 0) {
                  return Collections.emptyEnumeration();
              } else {
                  return new Enumerator<>(type, false);
              }
          }
      
          private <T> Iterator<T> getIterator(int type) {
              if (count == 0) {
                  return Collections.emptyIterator();
              } else {
                  return new Enumerator<>(type, true);
              }
          }
      
          // Views
      
          /**
           * Each of these fields are initialized to contain an instance of the
           * appropriate view the first time this view is requested.  The views are
           * stateless, so there's no reason to create more than one of each.
           */
          private transient volatile Set<K> keySet = null;
          private transient volatile Set<Map.Entry<K,V>> entrySet = null;
          private transient volatile Collection<V> values = null;
      
          /**
           * Returns a {@link Set} view of the keys contained in this map.
           * The set is backed by the map, so changes to the map are
           * reflected in the set, and vice-versa.  If the map is modified
           * while an iteration over the set is in progress (except through
           * the iterator's own <tt>remove</tt> operation), the results of
           * the iteration are undefined.  The set supports element removal,
           * which removes the corresponding mapping from the map, via the
           * <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
           * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>
           * operations.  It does not support the <tt>add</tt> or <tt>addAll</tt>
           * operations.
           *
           * @since 1.2
           */
          public Set<K> keySet() {
              if (keySet == null)
                  keySet = Collections.synchronizedSet(new KeySet(), this);
              return keySet;
          }
      
          private class KeySet extends AbstractSet<K> {
              public Iterator<K> iterator() {
                  return getIterator(KEYS);
              }
              public int size() {
                  return count;
              }
              public boolean contains(Object o) {
                  return containsKey(o);
              }
              public boolean remove(Object o) {
                  return Hashtable.this.remove(o) != null;
              }
              public void clear() {
                  Hashtable.this.clear();
              }
          }
      
          /**
           * Returns a {@link Set} view of the mappings contained in this map.
           * The set is backed by the map, so changes to the map are
           * reflected in the set, and vice-versa.  If the map is modified
           * while an iteration over the set is in progress (except through
           * the iterator's own <tt>remove</tt> operation, or through the
           * <tt>setValue</tt> operation on a map entry returned by the
           * iterator) the results of the iteration are undefined.  The set
           * supports element removal, which removes the corresponding
           * mapping from the map, via the <tt>Iterator.remove</tt>,
           * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt> and
           * <tt>clear</tt> operations.  It does not support the
           * <tt>add</tt> or <tt>addAll</tt> operations.
           *
           * @since 1.2
           */
          public Set<Map.Entry<K,V>> entrySet() {
              if (entrySet==null)
                  entrySet = Collections.synchronizedSet(new EntrySet(), this);
              return entrySet;
          }
      
          private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
              public Iterator<Map.Entry<K,V>> iterator() {
                  return getIterator(ENTRIES);
              }
      
              public boolean add(Map.Entry<K,V> o) {
                  return super.add(o);
              }
      
              public boolean contains(Object o) {
                  if (!(o instanceof Map.Entry))
                      return false;
                  Map.Entry entry = (Map.Entry)o;
                  Object key = entry.getKey();
                  Entry[] tab = table;
                  int hash = hash(key);
                  int index = (hash & 0x7FFFFFFF) % tab.length;
      
                  for (Entry e = tab[index]; e != null; e = e.next)
                      if (e.hash==hash && e.equals(entry))
                          return true;
                  return false;
              }
      
              public boolean remove(Object o) {
                  if (!(o instanceof Map.Entry))
                      return false;
                  Map.Entry<K,V> entry = (Map.Entry<K,V>) o;
                  K key = entry.getKey();
                  Entry[] tab = table;
                  int hash = hash(key);
                  int index = (hash & 0x7FFFFFFF) % tab.length;
      
                  for (Entry<K,V> e = tab[index], prev = null; e != null;
                       prev = e, e = e.next) {
                      if (e.hash==hash && e.equals(entry)) {
                          modCount++;
                          if (prev != null)
                              prev.next = e.next;
                          else
                              tab[index] = e.next;
      
                          count--;
                          e.value = null;
                          return true;
                      }
                  }
                  return false;
              }
      
              public int size() {
                  return count;
              }
      
              public void clear() {
                  Hashtable.this.clear();
              }
          }
      
          /**
           * Returns a {@link Collection} view of the values contained in this map.
           * The collection is backed by the map, so changes to the map are
           * reflected in the collection, and vice-versa.  If the map is
           * modified while an iteration over the collection is in progress
           * (except through the iterator's own <tt>remove</tt> operation),
           * the results of the iteration are undefined.  The collection
           * supports element removal, which removes the corresponding
           * mapping from the map, via the <tt>Iterator.remove</tt>,
           * <tt>Collection.remove</tt>, <tt>removeAll</tt>,
           * <tt>retainAll</tt> and <tt>clear</tt> operations.  It does not
           * support the <tt>add</tt> or <tt>addAll</tt> operations.
           *
           * @since 1.2
           */
          public Collection<V> values() {
              if (values==null)
                  values = Collections.synchronizedCollection(new ValueCollection(),
                                                              this);
              return values;
          }
      
          private class ValueCollection extends AbstractCollection<V> {
              public Iterator<V> iterator() {
                  return getIterator(VALUES);
              }
              public int size() {
                  return count;
              }
              public boolean contains(Object o) {
                  return containsValue(o);
              }
              public void clear() {
                  Hashtable.this.clear();
              }
          }
      
          // Comparison and hashing
      
          /**
           * Compares the specified Object with this Map for equality,
           * as per the definition in the Map interface.
           *
           * @param  o object to be compared for equality with this hashtable
           * @return true if the specified Object is equal to this Map
           * @see Map#equals(Object)
           * @since 1.2
           */
          public synchronized boolean equals(Object o) {
              if (o == this)
                  return true;
      
              if (!(o instanceof Map))
                  return false;
              Map<K,V> t = (Map<K,V>) o;
              if (t.size() != size())
                  return false;
      
              try {
                  Iterator<Map.Entry<K,V>> i = entrySet().iterator();
                  while (i.hasNext()) {
                      Map.Entry<K,V> e = i.next();
                      K key = e.getKey();
                      V value = e.getValue();
                      if (value == null) {
                          if (!(t.get(key)==null && t.containsKey(key)))
                              return false;
                      } else {
                          if (!value.equals(t.get(key)))
                              return false;
                      }
                  }
              } catch (ClassCastException unused)   {
                  return false;
              } catch (NullPointerException unused) {
                  return false;
              }
      
              return true;
          }
      
          /**
           * Returns the hash code value for this Map as per the definition in the
           * Map interface.
           *
           * @see Map#hashCode()
           * @since 1.2
           */
          public synchronized int hashCode() {
              /*
               * This code detects the recursion caused by computing the hash code
               * of a self-referential hash table and prevents the stack overflow
               * that would otherwise result.  This allows certain 1.1-era
               * applets with self-referential hash tables to work.  This code
               * abuses the loadFactor field to do double-duty as a hashCode
               * in progress flag, so as not to worsen the space performance.
               * A negative load factor indicates that hash code computation is
               * in progress.
               */
              int h = 0;
              if (count == 0 || loadFactor < 0)
                  return h;  // Returns zero
      
              loadFactor = -loadFactor;  // Mark hashCode computation in progress
              Entry[] tab = table;
              for (Entry<K,V> entry : tab)
                  while (entry != null) {
                      h += entry.hashCode();
                      entry = entry.next;
                  }
              loadFactor = -loadFactor;  // Mark hashCode computation complete
      
              return h;
          }
      
          /**
           * Save the state of the Hashtable to a stream (i.e., serialize it).
           *
           * @serialData The <i>capacity</i> of the Hashtable (the length of the
           *             bucket array) is emitted (int), followed by the
           *             <i>size</i> of the Hashtable (the number of key-value
           *             mappings), followed by the key (Object) and value (Object)
           *             for each key-value mapping represented by the Hashtable
           *             The key-value mappings are emitted in no particular order.
           */
          private void writeObject(java.io.ObjectOutputStream s)
                  throws IOException {
              Entry<K, V> entryStack = null;
      
              synchronized (this) {
                  // Write out the length, threshold, loadfactor
                  s.defaultWriteObject();
      
                  // Write out length, count of elements
                  s.writeInt(table.length);
                  s.writeInt(count);
      
                  // Stack copies of the entries in the table
                  for (int index = 0; index < table.length; index++) {
                      Entry<K,V> entry = table[index];
      
                      while (entry != null) {
                          entryStack =
                              new Entry<>(0, entry.key, entry.value, entryStack);
                          entry = entry.next;
                      }
                  }
              }
      
              // Write out the key/value objects from the stacked entries
              while (entryStack != null) {
                  s.writeObject(entryStack.key);
                  s.writeObject(entryStack.value);
                  entryStack = entryStack.next;
              }
          }
      
          /**
           * Reconstitute the Hashtable from a stream (i.e., deserialize it).
           */
          private void readObject(java.io.ObjectInputStream s)
               throws IOException, ClassNotFoundException
          {
              // Read in the length, threshold, and loadfactor
              s.defaultReadObject();
      
              // Read the original length of the array and number of elements
              int origlength = s.readInt();
              int elements = s.readInt();
      
              // Compute new size with a bit of room 5% to grow but
              // no larger than the original size.  Make the length
              // odd if it's large enough, this helps distribute the entries.
              // Guard against the length ending up zero, that's not valid.
              int length = (int)(elements * loadFactor) + (elements / 20) + 3;
              if (length > elements && (length & 1) == 0)
                  length--;
              if (origlength > 0 && length > origlength)
                  length = origlength;
      
              Entry<K,V>[] newTable = new Entry[length];
              threshold = (int) Math.min(length * loadFactor, MAX_ARRAY_SIZE + 1);
              count = 0;
              initHashSeedAsNeeded(length);
      
              // Read the number of elements and then all the key/value objects
              for (; elements > 0; elements--) {
                  K key = (K)s.readObject();
                  V value = (V)s.readObject();
                  // synch could be eliminated for performance
                  reconstitutionPut(newTable, key, value);
              }
              this.table = newTable;
          }
      
          /**
           * The put method used by readObject. This is provided because put
           * is overridable and should not be called in readObject since the
           * subclass will not yet be initialized.
           *
           * <p>This differs from the regular put method in several ways. No
           * checking for rehashing is necessary since the number of elements
           * initially in the table is known. The modCount is not incremented
           * because we are creating a new instance. Also, no return value
           * is needed.
           */
          private void reconstitutionPut(Entry<K,V>[] tab, K key, V value)
              throws StreamCorruptedException
          {
              if (value == null) {
                  throw new java.io.StreamCorruptedException();
              }
              // Makes sure the key is not already in the hashtable.
              // This should not happen in deserialized version.
              int hash = hash(key);
              int index = (hash & 0x7FFFFFFF) % tab.length;
              for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
                  if ((e.hash == hash) && e.key.equals(key)) {
                      throw new java.io.StreamCorruptedException();
                  }
              }
              // Creates the new entry.
              Entry<K,V> e = tab[index];
              tab[index] = new Entry<>(hash, key, value, e);
              count++;
          }
      
          /**
           * Hashtable bucket collision list entry
           */
          private static class Entry<K,V> implements Map.Entry<K,V> {
              int hash;
              final K key;
              V value;
              Entry<K,V> next;
      
              protected Entry(int hash, K key, V value, Entry<K,V> next) {
                  this.hash = hash;
                  this.key =  key;
                  this.value = value;
                  this.next = next;
              }
      
              protected Object clone() {
                  return new Entry<>(hash, key, value,
                                        (next==null ? null : (Entry<K,V>) next.clone()));
              }
      
              // Map.Entry Ops
      
              public K getKey() {
                  return key;
              }
      
              public V getValue() {
                  return value;
              }
      
              public V setValue(V value) {
                  if (value == null)
                      throw new NullPointerException();
      
                  V oldValue = this.value;
                  this.value = value;
                  return oldValue;
              }
      
              public boolean equals(Object o) {
                  if (!(o instanceof Map.Entry))
                      return false;
                  Map.Entry<?,?> e = (Map.Entry)o;
      
                  return key.equals(e.getKey()) && value.equals(e.getValue());
              }
      
              public int hashCode() {
                  return (Objects.hashCode(key) ^ Objects.hashCode(value));
              }
      
              public String toString() {
                  return key.toString()+"="+value.toString();
              }
          }
      
          // Types of Enumerations/Iterations
          private static final int KEYS = 0;
          private static final int VALUES = 1;
          private static final int ENTRIES = 2;
      
          /**
           * A hashtable enumerator class.  This class implements both the
           * Enumeration and Iterator interfaces, but individual instances
           * can be created with the Iterator methods disabled.  This is necessary
           * to avoid unintentionally increasing the capabilities granted a user
           * by passing an Enumeration.
           */
          private class Enumerator<T> implements Enumeration<T>, Iterator<T> {
              Entry[] table = Hashtable.this.table;
              int index = table.length;
              Entry<K,V> entry = null;
              Entry<K,V> lastReturned = null;
              int type;
      
              /**
               * Indicates whether this Enumerator is serving as an Iterator
               * or an Enumeration.  (true -> Iterator).
               */
              boolean iterator;
      
              /**
               * The modCount value that the iterator believes that the backing
               * Hashtable should have.  If this expectation is violated, the iterator
               * has detected concurrent modification.
               */
              protected int expectedModCount = modCount;
      
              Enumerator(int type, boolean iterator) {
                  this.type = type;
                  this.iterator = iterator;
              }
      
              public boolean hasMoreElements() {
                  Entry<K,V> e = entry;
                  int i = index;
                  Entry[] t = table;
                  /* Use locals for faster loop iteration */
                  while (e == null && i > 0) {
                      e = t[--i];
                  }
                  entry = e;
                  index = i;
                  return e != null;
              }
      
              public T nextElement() {
                  Entry<K,V> et = entry;
                  int i = index;
                  Entry[] t = table;
                  /* Use locals for faster loop iteration */
                  while (et == null && i > 0) {
                      et = t[--i];
                  }
                  entry = et;
                  index = i;
                  if (et != null) {
                      Entry<K,V> e = lastReturned = entry;
                      entry = e.next;
                      return type == KEYS ? (T)e.key : (type == VALUES ? (T)e.value : (T)e);
                  }
                  throw new NoSuchElementException("Hashtable Enumerator");
              }
      
              // Iterator methods
              public boolean hasNext() {
                  return hasMoreElements();
              }
      
              public T next() {
                  if (modCount != expectedModCount)
                      throw new ConcurrentModificationException();
                  return nextElement();
              }
      
              public void remove() {
                  if (!iterator)
                      throw new UnsupportedOperationException();
                  if (lastReturned == null)
                      throw new IllegalStateException("Hashtable Enumerator");
                  if (modCount != expectedModCount)
                      throw new ConcurrentModificationException();
      
                  synchronized(Hashtable.this) {
                      Entry[] tab = Hashtable.this.table;
                      int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length;
      
                      for (Entry<K,V> e = tab[index], prev = null; e != null;
                           prev = e, e = e.next) {
                          if (e == lastReturned) {
                              modCount++;
                              expectedModCount++;
                              if (prev == null)
                                  tab[index] = e.next;
                              else
                                  prev.next = e.next;
                              count--;
                              lastReturned = null;
                              return;
                          }
                      }
                      throw new ConcurrentModificationException();
                  }
              }
          }
      }
      

        



      Hashtable和HashMap都是通過維持一個Entry數組鏈表實現減值映射的。


              圖片復制于:http://blog.csdn.net/eaglex/article/details/6305997

      但是二者有所不同:

      1. 父類不同

      Hashtable繼承了Dictionary抽象類;HashMap繼承了AbstractMao類。

      Hashtable通過synchronized關鍵字,實現方法的線程安全。


      問題:

      1. 為什么使用int index = (hash & 0x7FFFFFFF) % tab.length;而不是直接用hash% tab.length?

      答:hash值可以是負數,那么-1%10=-1,Entry數組會發生越界。而0X7FFFFFFF的二進制是0111 1111 1111 1111 1111 1111 1111 1111,通過&操作,可以把hash值

      的最高位清0,避免越界。

      參考:Why does Java use (hash & 0x7FFFFFFF) % tab.length to decide the index of a key?










       

      posted @ 2014-12-30 16:39  bingtel  閱讀(209)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 亚洲一区二区三区影院| 国产成人精品视频网站| 亚洲欧洲av人一区二区| 人妻有码av中文字幕久久琪| 人妻另类 专区 欧美 制服| 国产精品一区二区不卡视频| 亚洲综合精品第一页| 国产精品福利中文字幕| 中文字幕人妻av第一区| 亚洲欧洲日产国无高清码图片| 久久精品天天中文字幕人妻| 国产又色又爽又黄的| 亚洲の无码国产の无码步美| 亚洲成AV人片在线观高清| 在线中文一区字幕对白| 看全色黄大黄大色免费久久| 亚洲第一综合天堂另类专| 九九热视频在线精品18| 久久亚洲精品亚洲人av| 国产91特黄特色A级毛片| 久久精品免视看国产成人| 亚洲人妻中文字幕一区| 99精品免费久久久久久久久日本| 久久亚洲精品中文字幕无| 国产在线拍揄自揄视频网试看 | 视频一区二区三区四区五区| 日韩av一区二区高清不卡| 亚洲国产99精品国自产拍| 国产激情无码一区二区三区| 视频一区二区三区刚刚碰| 影视先锋av资源噜噜| 国产日产欧美最新| 亚洲国产成人久久综合同性| 色综合天天综合网中文伊| 国产亚洲一二三区精品| 亚洲中文字幕伊人久久无码 | 人妻无码中文专区久久app| 四虎国产精品成人免费久久| 99久久机热/这里只有精品| 天天躁日日躁狠狠躁性色avq| 免费看视频的网站|