Java容器四:Hashtable

Hashtable

Map, Cloneable, Serializable
–>Dictionary


本文中的Hashtable主要与HashMap进行对比,其中有两个主要的区别,一是Hashtable中提供的公共方法中都由synchronized修饰,因此是保证线程安全的,而HashMap并未保证线程安全性。但Hashtable仍具有fail-fast特性,在得到iterator之后,若通过该迭代器之外的方式修改了表结构,再次调用该迭代器的方法时会抛出ConcurrentModificationException。第二是Hashtable的key值和value值不能为null(1.8中的方法仅要求value不能为null),而HashMap是可以为null的。在Hashtable中也使用桶这一概念,并且出现hash冲突时使用链表解决冲突。

初始化默认值

Hashtable的初始化默认值是直接写死在构造函数中的。

//  桶的最大大小,减8是因为很多时候数组还需要一部分空间存储本身的信息
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
public Hashtable() {
    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)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
}

若参数initialCapacity输入0,则初始化桶大小为1。和HashMap等容器不同,Hashtable是在初始化的时候就给table分配了内存空间。

成员变量

// table中的每一个元素代表一个桶
private transient Entry<?,?>[] table;
// 已储存的元素个数
private transient int count;
// 定义为(capacity(table.size) * loadFactor),count超过该值即重新分配空间
private int threshold;
// 负载(默认值或赋新值)
private float loadFactor;
// 实现fail-fast
private transient int modCount = 0;

桶定位和扩容方式

桶定位

Hashtable中根据key值计算hash值的方法为直接调用Object.hashCode计算。但计算桶标号的方法和HashMap不同,是使用了hash值的后31位与桶的数量取了一个模值运算。

Entry<?,?> tab[] = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;

扩容

HashMap的直接扩大两倍不同,Hashtable是将桶数量扩大为当前数量的两倍再加上1,保证桶数量是奇数(最好是保证是素数,但不太好实现,因此仅保证了奇数条件)。

protected void rehash() {
    int oldCapacity = table.length;
    Entry<?,?>[] 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<?,?>[] newMap = new Entry<?,?>[newCapacity];

    modCount++;
    threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
    table = newMap;

    for (int i = oldCapacity ; i-- > 0 ;) {
        for (Entry<K,V> old = (Entry<K,V>)oldMap[i] ; old != null ; ) {
            Entry<K,V> e = old;
            old = old.next;

            int index = (e.hash & 0x7FFFFFFF) % newCapacity;
            e.next = (Entry<K,V>)newMap[index];
            newMap[index] = e;
        }
    }
}

entrySet,keySet,Values

得到这三个Set的方法类似,都是通过调用Collections.synchronizedCollection方法实现,将当前Hashtable对象作为锁,保证使用这三个Set时的线程安全问题。

private transient volatile Set<K> keySet;
private transient volatile Set<Map.Entry<K,V>> entrySet;
private transient volatile Collection<V> values;
keySet = Collections.synchronizedSet(new KeySet(), this);
entrySet = Collections.synchronizedSet(new EntrySet(),this);
values = Collections.synchronizedCollection(new ValueCollection(),this);

枚举器,迭代器

Hashtable中得到枚举器和迭代器都是通过Enumerator类实现,可以看到,Enumerator实现了枚举器和迭代器两个接口,并通过iterator标识确认返回的是枚举器还是迭代器。同时,通过type确定需要返回的是key,value或entry的枚举器/迭代器。

// Types of Enumerations/Iterations
private static final int KEYS = 0;
private static final int VALUES = 1;
private static final int ENTRIES = 2;
private class Enumerator<T> implements Enumeration<T>, Iterator<T>{
Entry<?,?>[] table = Hashtable.this.table;
int index = table.length;
Entry<?,?> entry;
Entry<?,?> lastReturned;
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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值