hashtable.java

来自「linux下建立JAVA虚拟机的源码KAFFE」· Java 代码 · 共 1,252 行 · 第 1/3 页

JAVA
1,252
字号
   * @return the prior mapping of the key, or null if there was none   * @throws NullPointerException if key or value is null   * @see #get(Object)   * @see Object#equals(Object)   */  public synchronized Object put(Object key, Object value)  {    int idx = hash(key);    HashEntry e = buckets[idx];    // Check if value is null since it is not permitted.    if (value == null)      throw new NullPointerException();    while (e != null)      {        if (e.key.equals(key))          {            // Bypass e.setValue, since we already know value is non-null.            Object r = e.value;            e.value = value;            return r;          }        else          {            e = e.next;          }      }    // At this point, we know we need to add a new entry.    modCount++;    if (++size > threshold)      {        rehash();        // Need a new hash value to suit the bigger table.        idx = hash(key);      }    e = new HashEntry(key, value);    e.next = buckets[idx];    buckets[idx] = e;    return null;  }  /**   * Removes from the table and returns the value which is mapped by the   * supplied key. If the key maps to nothing, then the table remains   * unchanged, and <code>null</code> is returned.   *   * @param key the key used to locate the value to remove   * @return whatever the key mapped to, if present   */  public synchronized Object remove(Object key)  {    int idx = hash(key);    HashEntry e = buckets[idx];    HashEntry last = null;    while (e != null)      {        if (e.key.equals(key))          {            modCount++;            if (last == null)              buckets[idx] = e.next;            else              last.next = e.next;            size--;            return e.value;          }        last = e;        e = e.next;      }    return null;  }  /**   * Copies all elements of the given map into this hashtable.  However, no   * mapping can contain null as key or value.  If this table already has   * a mapping for a key, the new mapping replaces the current one.   *   * @param m the map to be hashed into this   * @throws NullPointerException if m is null, or contains null keys or values   */  public synchronized void putAll(Map m)  {    Iterator itr = m.entrySet().iterator();    while (itr.hasNext())      {        Map.Entry e = (Map.Entry) itr.next();        // Optimize in case the Entry is one of our own.        if (e instanceof AbstractMap.BasicMapEntry)          {            AbstractMap.BasicMapEntry entry = (AbstractMap.BasicMapEntry) e;            put(entry.key, entry.value);          }        else          {            put(e.getKey(), e.getValue());          }      }  }  /**   * Clears the hashtable so it has no keys.  This is O(1).   */  public synchronized void clear()  {    if (size > 0)      {        modCount++;        Arrays.fill(buckets, null);        size = 0;      }  }  /**   * Returns a shallow clone of this Hashtable. The Map itself is cloned,   * but its contents are not.  This is O(n).   *   * @return the clone   */  public synchronized Object clone()  {    Hashtable copy = null;    try      {        copy = (Hashtable) super.clone();      }    catch (CloneNotSupportedException x)      {        // This is impossible.      }    copy.buckets = new HashEntry[buckets.length];    copy.putAllInternal(this);    // Clear the caches.    copy.keys = null;    copy.values = null;    copy.entries = null;    return copy;  }  /**   * Converts this Hashtable to a String, surrounded by braces, and with   * key/value pairs listed with an equals sign between, separated by a   * comma and space. For example, <code>"{a=1, b=2}"</code>.<p>   *   * NOTE: if the <code>toString()</code> method of any key or value   * throws an exception, this will fail for the same reason.   *   * @return the string representation   */  public synchronized String toString()  {    // Since we are already synchronized, and entrySet().iterator()    // would repeatedly re-lock/release the monitor, we directly use the    // unsynchronized EntryIterator instead.    Iterator entries = new EntryIterator();    StringBuffer r = new StringBuffer("{");    for (int pos = size; pos > 0; pos--)      {        r.append(entries.next());        if (pos > 1)          r.append(", ");      }    r.append("}");    return r.toString();  }  /**   * Returns a "set view" of this Hashtable's keys. The set is backed by   * the hashtable, so changes in one show up in the other.  The set supports   * element removal, but not element addition.  The set is properly   * synchronized on the original hashtable.  Sun has not documented the   * proper interaction of null with this set, but has inconsistent behavior   * in the JDK. Therefore, in this implementation, contains, remove,   * containsAll, retainAll, removeAll, and equals just ignore a null key   * rather than throwing a {@link NullPointerException}.   *   * @return a set view of the keys   * @see #values()   * @see #entrySet()   * @since 1.2   */  public Set keySet()  {    if (keys == null)      {        // Create a synchronized AbstractSet with custom implementations of        // those methods that can be overridden easily and efficiently.        Set r = new AbstractSet()        {          public int size()          {            return size;          }          public Iterator iterator()          {            return new KeyIterator();          }          public void clear()          {            Hashtable.this.clear();          }          public boolean contains(Object o)          {            if (o == null)              return false;            return containsKey(o);          }          public boolean remove(Object o)          {            return Hashtable.this.remove(o) != null;          }        };        // We must specify the correct object to synchronize upon, hence the        // use of a non-public API        keys = new Collections.SynchronizedSet(this, r);      }    return keys;  }  /**   * Returns a "collection view" (or "bag view") of this Hashtable's values.   * The collection is backed by the hashtable, so changes in one show up   * in the other.  The collection supports element removal, but not element   * addition.  The collection is properly synchronized on the original   * hashtable.  Sun has not documented the proper interaction of null with   * this set, but has inconsistent behavior in the JDK. Therefore, in this   * implementation, contains, remove, containsAll, retainAll, removeAll, and   * equals just ignore a null value rather than throwing a   * {@link NullPointerException}.   *   * @return a bag view of the values   * @see #keySet()   * @see #entrySet()   * @since 1.2   */  public Collection values()  {    if (values == null)      {        // We don't bother overriding many of the optional methods, as doing so        // wouldn't provide any significant performance advantage.        Collection r = new AbstractCollection()        {          public int size()          {            return size;          }          public Iterator iterator()          {            return new ValueIterator();          }          public void clear()          {            Hashtable.this.clear();          }        };        // We must specify the correct object to synchronize upon, hence the        // use of a non-public API        values = new Collections.SynchronizedCollection(this, r);      }    return values;  }  /**   * Returns a "set view" of this Hashtable's entries. The set is backed by   * the hashtable, so changes in one show up in the other.  The set supports   * element removal, but not element addition.  The set is properly   * synchronized on the original hashtable.  Sun has not documented the   * proper interaction of null with this set, but has inconsistent behavior   * in the JDK. Therefore, in this implementation, contains, remove,   * containsAll, retainAll, removeAll, and equals just ignore a null entry,   * or an entry with a null key or value, rather than throwing a   * {@link NullPointerException}. However, calling entry.setValue(null)   * will fail.   * <p>   *   * Note that the iterators for all three views, from keySet(), entrySet(),   * and values(), traverse the hashtable in the same sequence.   *   * @return a set view of the entries   * @see #keySet()   * @see #values()   * @see Map.Entry   * @since 1.2   */  public Set entrySet()  {    if (entries == null)      {        // Create an AbstractSet with custom implementations of those methods        // that can be overridden easily and efficiently.        Set r = new AbstractSet()        {          public int size()          {            return size;          }          public Iterator iterator()          {            return new EntryIterator();          }          public void clear()          {            Hashtable.this.clear();          }          public boolean contains(Object o)          {            return getEntry(o) != null;          }          public boolean remove(Object o)          {            HashEntry e = getEntry(o);            if (e != null)              {                Hashtable.this.remove(e.key);                return true;              }            return false;          }        };        // We must specify the correct object to synchronize upon, hence the        // use of a non-public API        entries = new Collections.SynchronizedSet(this, r);      }    return entries;  }  /**   * Returns true if this Hashtable equals the supplied Object <code>o</code>.   * As specified by Map, this is:   * <code>   * (o instanceof Map) && entrySet().equals(((Map) o).entrySet());   * </code>   *   * @param o the object to compare to   * @return true if o is an equal map   * @since 1.2   */  public boolean equals(Object o)  {    // no need to synchronize, entrySet().equals() does that    if (o == this)      return true;    if (!(o instanceof Map))      return false;    return entrySet().equals(((Map) o).entrySet());  }  /**   * Returns the hashCode for this Hashtable.  As specified by Map, this is   * the sum of the hashCodes of all of its Map.Entry objects   *   * @return the sum of the hashcodes of the entries   * @since 1.2   */  public synchronized int hashCode()  {    // Since we are already synchronized, and entrySet().iterator()    // would repeatedly re-lock/release the monitor, we directly use the    // unsynchronized EntryIterator instead.    Iterator itr = new EntryIterator();    int hashcode = 0;    for (int pos = size; pos > 0; pos--)      hashcode += itr.next().hashCode();    return hashcode;  }  /**   * Helper method that returns an index in the buckets array for `key'   * based on its hashCode().   *   * @param key the key   * @return the bucket number   * @throws NullPointerException if key is null   */  private int hash(Object key)  {    // Note: Inline Math.abs here, for less method overhead, and to avoid    // a bootstrap dependency, since Math relies on native methods.    int hash = key.hashCode() % buckets.length;    return hash < 0 ? -hash : hash;  }  /**   * Helper method for entrySet(), which matches both key and value   * simultaneously. Ignores null, as mentioned in entrySet().   *   * @param o the entry to match   * @return the matching entry, if found, or null   * @see #entrySet()   */  // Package visible, for use in nested classes.  HashEntry getEntry(Object o)  {    if (! (o instanceof Map.Entry))      return null;    Object key = ((Map.Entry) o).getKey();    if (key == null)      return null;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?