JDK1.1 HashTable 源代码分析

package test.shenli.java.util;

import java.util.Enumeration;
 
/**
 * Object that wraps entries in the hash-table
 * @author Morten Jorgensen
 * 哈希表实体类
 */
class HashtableEntry {
    int hash;            //哈希值
    Object key;          //键对象
    Object value;        //值对象
    HashtableEntry next; //链表结构,next指向下一个实体
 
    /**
     * 实现clone方法,复制自己(原型模式)
     */
    protected Object clone() {
        HashtableEntry entry = new HashtableEntry();
        entry.hash = hash;
        entry.key = key;
        entry.value = value;
        //如果next不为空,将entry的next指向next的副本,在调用next.clone时
        //会继续判断next.next,并继续复制下去,最终会复制整个链表,所以改变
        //clone,将不会更改原对象
        entry.next = (next != null) ? (HashtableEntry)next.clone() : null;
        return entry;
    }
}
 
/**
 * The main hash-table implementation
 */
public class Hashtable {
 
    private transient HashtableEntry table[]; // hash-table entries 实体数组
    private transient int count;              // number of entries  实体数组数量
    private int threshold;                    // current size of hash-tabke  阀值
    private float loadFactor;                 // load factor        负载因子
 
    /**
     * Constructs a new, empty hashtable with the specified initial
     * capacity and the specified load factor.
     * @param initialCapacity: 初始容量
     * @param loadFactor 负载因子
     */
    public Hashtable(int initialCapacity, float loadFactor) {
        if (initialCapacity <= 0) initialCapacity = 11;  //最小初始容量为1
        if (loadFactor <= 0.0) loadFactor = 0.75f;       //最小负载因子是0.75
        this.loadFactor = loadFactor;                    
        table = new HashtableEntry[initialCapacity];     //使用初始容量,初始化实体数组
        threshold = (int)(initialCapacity * loadFactor); //初始化阀值=初始容量x负载因子
    }
 
    /**
     * Constructs a new, empty hashtable with the specified initial capacity
     * and default load factor.
     * 重载构造函数(一个参数)
     * @param initialCapacity 初始容量
     */
    public Hashtable(int initialCapacity) {
        this(initialCapacity, 0.75f);
    }
 
    /**
     * Constructs a new, empty hashtable with a default capacity and load
     * factor.
     * 重载构造函数(没有参数)
     */
    public Hashtable() {
        this(101, 0.75f);
    }
 
    /**
     * Returns the number of keys in this hashtable.
     * @Return 返回实体数组数量
     */
    public int size() {
        return count;
    }
 
    /**
     * Tests if this hashtable maps no keys to values.
     * @return 返回实体数组数量是否为0
     */
    public boolean isEmpty() {
        return count == 0;
    }
 
    /**
     * Returns an enumeration of the keys in this hashtable.
     * 使用HashtableEnumerator构造一个keys为true的枚举类
     * (在next的时候根据keys为tru或false返回e.key或e.value)
     */
    public Enumeration keys() {
        return new HashtableEnumerator(table, true);
    }
 
    /**
     * Returns an enumeration of the values in this hashtable.
     * Use the Enumeration methods on the returned object to fetch the elements
     * sequentially.
     * 使用HashtableEnumerator构造一个keys为false的枚举类
     * (在next的时候根据keys为tru或false返回e.key或e.value)
     */
    public Enumeration elements() {
        return new HashtableEnumerator(table, false);
    }
 
    /**
     * Tests if some key maps into the specified value in this hashtable.
     * This operation is more expensive than the <code>containsKey</code>
     * method.
     * 判断一个值是否在实体数组的value里
     */
    public boolean contains(Object value) {
    //入参为空,直接报空指针异常
        if (value == null) throw new NullPointerException();
 
        int i;
        HashtableEntry e;
        HashtableEntry tab[] = table;
        
        //循环数组比对值是否相同
        for (i = tab.length ; i-- > 0 ;) {
            for (e = tab[i] ; e != null ; e = e.next) {
                if (e.value.equals(value)) {
                    return true;
                }
            }
        }
        return false;
    }
 
    /**
     * Tests if the specified object is a key in this hashtable.
     */
    public boolean containsKey(Object key) {
        HashtableEntry e;
        HashtableEntry tab[] = table;
        /**
         * Object.HashCode
         * 返回该对象的哈希码值。支持此方法是为了提高哈希表(例如 java.util.Hashtable 提供的哈希表)的性能。 
         * hashCode 的常规协定是: 
         *
         * 在 Java 应用程序执行期间,在对同一对象多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是将对象进行 equals 比较时所用的信息没有被修改。
         * 从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。 
         * 如果根据 equals(Object) 方法,两个对象是相等的,那么对这两个对象中的每个对象调用 hashCode 方法都必须生成相同的整数结果。 
         * 如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么对这两个对象中的任一对象上调用 hashCode 方法不 要求一定生成不同的整数结果。
         * 但是,程序员应该意识到,为不相等的对象生成不同整数结果可以提高哈希表的性能。 
         *
         * 实际上,由 Object 类定义的 hashCode 方法确实会针对不同的对象返回不同的整数。
         *(这一般是通过将该对象的内部地址转换成一个整数来实现的,但是 JavaTM 编程语言不需要这种实现技巧。)
         */
        //调用Object的hashCode方法(native)
        int hash = key.hashCode();
        //-1 & 0x7FFFFFFF == Integer.MAX_VALUE
        int index = (hash & 0x7FFFFFFF) % tab.length;
 
        for (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 in this hashtable.
     */
    public Object get(Object key) {
        HashtableEntry e;
        HashtableEntry tab[] = table;
        int hash = key.hashCode();
        int index = (hash & 0x7FFFFFFF) % tab.length;
 
        //搜索链表上所有的值
        for (e = tab[index] ; e != null ; e = e.next)
            if ((e.hash == hash) && e.key.equals(key))
                return e.value;
 
        return null;
    }
 
    /**
     * Rehashes the contents of the hashtable into a hashtable with a
     * larger capacity. This method is called automatically when the
     * number of keys in the hashtable exceeds this hashtable's capacity
     * and load factor.
     * 将Hashtable的内容到一个大容量的哈希表。自动调用该方法时,在哈希表中的键的数目超过了哈希表的容量和加载因子。
     */
    protected void rehash() {
        HashtableEntry e, old;
        int i, index;
        int oldCapacity = table.length;
        HashtableEntry oldTable[] = table;
 
        int newCapacity = oldCapacity * 2 + 1;
        HashtableEntry newTable[] = new HashtableEntry[newCapacity];
 
        threshold = (int)(newCapacity * loadFactor);
        table = newTable;
 
        //粗略的理解是,根据新的容量计算新的hashCode后,作为数组下标,重建数组
        for (i = oldCapacity ; i-- > 0 ;) {
            for (old = oldTable[i] ; old != null ; ) {
                e = old;
                old = old.next;
                index = (e.hash & 0x7FFFFFFF) % newCapacity;
                e.next = newTable[index];
                newTable[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.
     */
    public Object put(Object key, Object value) {
        // Make sure the value is not null
        if (value == null) throw new NullPointerException();
 
        // Makes sure the key is not already in the hashtable.
        HashtableEntry e;
        HashtableEntry tab[] = table;
        int hash = key.hashCode();
        int index = (hash & 0x7FFFFFFF) % tab.length;
 
        for (e = tab[index] ; e != null ; e = e.next) {
            if ((e.hash == hash) && e.key.equals(key)) {
                Object old = e.value;
                e.value = value;
                return old;
            }
        }
 
        // Rehash the table if the threshold is exceeded
        if (count >= threshold) {
            rehash();
            return put(key, value);
        }
 
        // Creates the new entry.
        //如果key的hashCode相同,那么就往链表里追加一个对象!!!
        e = new HashtableEntry();
        e.hash = hash;
        e.key = key;
        e.value = value;
        e.next = tab[index];
        tab[index] = 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.
     */
    public Object remove(Object key) {
        HashtableEntry e, prev;
        HashtableEntry tab[] = table;
        int hash = key.hashCode();
        int index = (hash & 0x7FFFFFFF) % tab.length;
        for (e = tab[index], prev = null ; e != null ; prev = e, e = e.next) {
            if ((e.hash == hash) && e.key.equals(key)) {
                if (prev != null)
                    prev.next = e.next;
                else
                    tab[index] = e.next;
                count--;
                return e.value;
            }
        }
        return null;
    }
 
    /**
     * Clears this hashtable so that it contains no keys.
     */
    public void clear() {
        HashtableEntry tab[] = table;
        for (int index = tab.length; --index >= 0; )
            tab[index] = null;
        count = 0;
    }
 
    /**
     * Returns a rather long string representation of this hashtable.
     * Handy for debugging - leave it here!!!
     */
    public String toString() {
        int i;
        int max = size() - 1;
        StringBuffer buf = new StringBuffer();
        Enumeration k = keys();
        Enumeration e = elements();
        buf.append("{");
 
        for (i = 0; i <= max; i++) {
            String s1 = k.nextElement().toString();
            String s2 = e.nextElement().toString();
            buf.append(s1).append('=').append(s2);
            if (i < max) buf.append(", ");
        }
        buf.append("}");
        return buf.toString();
    }
 
    /**
     * A hashtable enumerator class.  This class should remain opaque
     * to the client. It will use the Enumeration interface.
     */
    class HashtableEnumerator implements Enumeration {
        boolean keys;
        int index;
        HashtableEntry table[];
        HashtableEntry entry;
 
        HashtableEnumerator(HashtableEntry table[], boolean keys) {
            this.table = table;
            this.keys = keys;
            this.index = table.length;
        }
 
        public boolean hasMoreElements() {
            if (entry != null) {
                return true;
            }
            while (index-- > 0) {
                if ((entry = table[index]) != null) {
                    return true;
                }
            }
            return false;
        }
 
        public Object nextElement() {
            if (entry == null) {
                while ((index-- > 0) && ((entry = table[index]) == null));
            }
            if (entry != null) {
                HashtableEntry e = entry;
                entry = e.next;
                return keys ? e.key : e.value;
            }
            return null;
        }
    }
 
}


你可能感兴趣的:(jdk,Hashtable)