JDK源码学习09----HashTable

来源:互联网 发布:java全局map 编辑:程序博客网 时间:2024/06/15 20:07

                                                         JDK源码学习09----HashTable

1.HashTable简介

Hashtable 也是一个散列表,它存储的内容是键值对(key-value)映射
Hashtable 继承于Dictionary,实现了Map、Cloneable、java.io.Serializable接口。
Hashtable 的函数都是同步的,这意味着它是线程安全的。它的key、value都不可以为null。此外,Hashtable中的映射不是有序的。

public class Hashtable<K,V> extends Dictionary<K,V>    implements Map<K,V>, Cloneable, java.io.Serializable { }


2.HashTable的成员变量

// 默认构造函数。public Hashtable() // 指定“容量大小”的构造函数public Hashtable(int initialCapacity) // 指定“容量大小”和“加载因子”的构造函数public Hashtable(int initialCapacity, float loadFactor) // 包含“子Map”的构造函数public Hashtable(Map<? extends K, ? extends V> t)
 它包括几个重要的成员变量:tablecountthresholdloadFactormodCount
  table是一个Entry[]数组类型,而Entry实际上就是一个单向链表。哈希表的"key-value键值对"都是存储在Entry数组中的。 
  count是Hashtable的大小,它是Hashtable保存的键值对的数量。 
  threshold是Hashtable的阈值,用于判断是否需要调整Hashtable的容量。threshold的值="容量*加载因子"。
  loadFactor就是加载因子。 
  modCount是用来实现fail-fast机制的
3.HashTable 的构造函数

// 默认构造函数。public Hashtable() {    // 默认构造函数,指定的容量大小是11;加载因子是0.75    this(11, 0.75f);}// 指定“容量大小”的构造函数public Hashtable(int initialCapacity) {    this(initialCapacity, 0.75f);}// 指定“容量大小”和“加载因子”的构造函数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)(initialCapacity * loadFactor);}// 包含“子Map”的构造函数public Hashtable(Map<? extends K, ? extends V> t) {    this(Math.max(2*t.size(), 11), 0.75f);    // 将“子Map”的全部元素都添加到Hashtable中    putAll(t);}

4.HashTable常用方法

4.1V put(K key, V value)

public synchronized V put(K key, V value) {    // Hashtable中不能插入value为null的元素!!!    if (value == null) {        throw new NullPointerException();    }    // 若“Hashtable中已存在键为key的键值对”,    // 则用“新的value”替换“旧的value”    Entry tab[] = table;    int hash = key.hashCode();    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;            }    }    // 若“Hashtable中不存在键为key的键值对”,    // (01) 将“修改统计数”+1    modCount++;    // (02) 若“Hashtable实际容量” > “阈值”(阈值=总的容量 * 加载因子)    //  则调整Hashtable的大小    if (count >= threshold) {        // Rehash the table if the threshold is exceeded        rehash();        tab = table;        index = (hash & 0x7FFFFFFF) % tab.length;    }    // (03) 将“Hashtable中index”位置的Entry(链表)保存到e中    Entry<K,V> e = tab[index];    // (04) 创建“新的Entry节点”,并将“新的Entry”插入“Hashtable的index位置”,并设置e为“新的Entry”的下一个元素(即“新Entry”为链表表头)。            tab[index] = new Entry<K,V>(hash, key, value, e);    // (05) 将“Hashtable的实际容量”+1    count++;    return null;}

4.2 V get(Object key)

public synchronized V get(Object key) {    Entry tab[] = table;    int hash = key.hashCode();    // 计算索引值,    int index = (hash & 0x7FFFFFFF) % tab.length;    // 找到“key对应的Entry(链表)”,然后在链表中找出“哈希值”和“键值”与key都相等的元素    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;}
4.3 clear()

public synchronized void clear() {2     Entry tab[] = table;3     modCount++;4     for (int index = tab.length; --index >= 0; )5         tab[index] = null;6     count = 0;7 }
4.4contains() 和 containsValue()

public boolean containsValue(Object value) {    return contains(value);}public synchronized boolean contains(Object value) {    // Hashtable中“键值对”的value不能是null,    // 若是null的话,抛出异常!    if (value == null) {        throw new NullPointerException();    }    // 从后向前遍历table数组中的元素(Entry)    // 对于每个Entry(单向链表),逐个遍历,判断节点的值是否等于value    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;}
4.5void putAll(Map<? extends K, ? extends V> t)

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()); }
4.6 V remove(Object key)
public synchronized V remove(Object key) {    Entry tab[] = table;    int hash = key.hashCode();    int index = (hash & 0x7FFFFFFF) % tab.length;    // 找到“key对应的Entry(链表)”    // 然后在链表中找出要删除的节点,并删除该节点。    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;}
5.HashMap的数据节点Entry<K,V>类

private static class Entry<K,V> implements Map.Entry<K,V> {    // 哈希值    int hash;    K key;    V value;    // 指向的下一个Entry,即链表的下一个节点    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<K,V>(hash, key, value,              (next==null ? null : (Entry<K,V>) next.clone()));    }    public K getKey() {        return key;    }    public V getValue() {        return value;    }    // 设置value。若value是null,则抛出异常。    public V setValue(V value) {        if (value == null)            throw new NullPointerException();        V oldValue = this.value;        this.value = value;        return oldValue;    }    // 覆盖equals()方法,判断两个Entry是否相等。    // 若两个Entry的key和value都相等,则认为它们相等。    public boolean equals(Object o) {        if (!(o instanceof Map.Entry))            return false;        Map.Entry e = (Map.Entry)o;        return (key==null ? e.getKey()==null : key.equals(e.getKey())) &&           (value==null ? e.getValue()==null : value.equals(e.getValue()));    }    public int hashCode() {        return hash ^ (value==null ? 0 : value.hashCode());    }    public String toString() {        return key.toString()+"="+value.toString();    }}

6.总结
a.HashTable 是同步的,线程安全,适合多线程。

b.HashTable的键值都 不能 为null.

c.HashTable和HashMap一样,也是通过拉链法解决hash冲突的。



0 0