【Java集合源码剖析】Hashtable源码剖析

本文详细剖析了Java集合中的Hashtable类,介绍了其线程安全的特性、默认容量、存储结构以及解决冲突的方法。对比HashMap,总结了两者在容量、key和value的限制、扩容策略及计算hash值方式上的差异。
摘要由CSDN通过智能技术生成

转载请注明出处:http://blog.csdn.net/ns_code/article/details/36191279


Hashtable简介

    Hashtable同样是基于哈希表实现的,同样每个元素是一个key-value对,其内部也是通过单链表解决冲突问题,容量不足(超过了阀值)时,同样会自动增长。

    Hashtable也是JDK1.0引入的类,是线程安全的,能用于多线程环境中。

    Hashtable同样实现了Serializable接口,它支持序列化,实现了Cloneable接口,能被克隆

HashTable源码剖析

    Hashtable的源码的很多实现都与HashMap差不多,源码如下(加入了比较详细的注释):

package java.util;  
import java.io.*;  
 
public class Hashtable<K,V>  
    extends Dictionary<K,V>  
    implements Map<K,V>, Cloneable, java.io.Serializable {  
 
    // 保存key-value的数组。  
    // Hashtable同样采用单链表解决冲突,每一个Entry本质上是一个单向链表  
    private transient Entry[] table;  
 
    // Hashtable中键值对的数量  
    private transient int count;  
 
    // 阈值,用于判断是否需要调整Hashtable的容量(threshold = 容量*加载因子)  
    private int threshold;  
 
    // 加载因子  
    private float loadFactor;  
 
    // Hashtable被改变的次数,用于fail-fast机制的实现  
    private transient int modCount = 0;  
 
    // 序列版本号  
    private static final long serialVersionUID = 1421746759512286392L;  
 
    // 指定“容量大小”和“加载因子”的构造函数  
    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);  
    }  
 
    // 指定“容量大小”的构造函数  
    public Hashtable(int initialCapacity) {  
        this(initialCapacity, 0.75f);  
    }  
 
    // 默认构造函数。  
    public Hashtable() {  
        // 默认构造函数,指定的容量大小是11;加载因子是0.75  
        this(11, 0.75f);  
    }  
 
    // 包含“子Map”的构造函数  
    public Hashtable(Map<? extends K, ? extends V> t) {  
        this(Math.max(2*t.size(), 11), 0.75f);  
        // 将“子Map”的全部元素都添加到Hashtable中  
        putAll(t);  
    }  
 
    public synchronized int size() {  
        return count;  
    }  
 
    public synchronized boolean isEmpty() {  
        return count == 0;  
    }  
 
    // 返回“所有key”的枚举对象  
    public synchronized Enumeration<K> keys() {  
        return this.<K>getEnumeration(KEYS);  
    }  
 
    // 返回“所有value”的枚举对象  
    public synchronized Enumeration<V> elements() {  
        return this.<V>getEnumeration(VALUES);  
    }  
 
    // 判断Hashtable是否包含“值(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;  
    }  
 
    public boolean containsValue(Object value) {  
        return contains(value);  
    }  
 
    // 判断Hashtable是否包含key  
    public synchronized boolean containsKey(Object key) {  
        Entry tab[] = table;  
		//计算hash值,直接用key的hashCode代替
        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 true;  
            }  
        }  
        return false;  
    }  
 
    // 返回key对应的value,没有的话返回null  
    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;  
    }  
 
    // 调整Hashtable的长度,将长度变成原来的2倍+1 
    protected void rehash() {  
        int oldCapacity = table.length;  
        Entry[] oldMap = table;  
 
		//创建新容量大小的Entry数组
        int newCapacity = oldCapacity * 2 + 1;  
        Entry[] newMap = new Entry[newCapacity];  
 
        modCount++;  
        threshold = (int)(newCapacity * loadFactor);  
        table = newMap;  
		
		//将“旧的Hashtable”中的元素复制到“新的Hashtable”中
		for (int i = oldCapacity ; i-- > 0 ;) {  
            for (Entry<K,V> old = oldMap[i] ; old != null ; ) {  
                Entry<K,V> e = old;  
                old = old.next;  
				//重新计算index
                int index = (e.hash & 0x7FFFFFFF) % newCapaci
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值