Java 集合系列-第10篇-Hashtable介绍

Hashtable介绍

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

Hashtable 的实例有两个参数影响其性能:初始容量 和 加载因子。容量 是哈希表中桶 的数量,初始容量 就是哈希表建立时的容量。注意,哈希表的状态为 open:在发生“哈希冲突”的状况下,单个桶会存储多个条目,这些条目必须按顺序搜索。加载因子 是对哈希表在其容量自动增长以前能够达到多满的一个尺度。初始容量和加载因子这两个参数只是对该实现的提示。关于什么时候以及是否调用 rehash 方法的具体细节则依赖于该实现。 一般,默认加载因子是 0.75, 这是在时间和空间成本上寻求一种折衷。加载因子太高虽然减小了空间开销,但同时也增长了查找某个条目的时间(在大多数 Hashtable 操做中,包括 get 和 put 操做,都反映了这一点)。java

Hashtable的构造函数

// 默认构造函数。
public Hashtable() 

// 指定“容量大小”的构造函数
public Hashtable(int initialCapacity) 

// 指定“容量大小”和“加载因子”的构造函数
public Hashtable(int initialCapacity, float loadFactor) 

// 包含“子Map”的构造函数
public Hashtable(Map<? extends K, ? extends V> t)

Hashtable的继承关系

java.lang.Object
   ↳     java.util.Dictionary<K, V>
         ↳     java.util.Hashtable<K, V>

public class Hashtable<K,V> extends Dictionary<K,V>
    implements Map<K,V>, Cloneable, java.io.Serializable { }
  • Hashtable继承于Dictionary类,实现了Map接口。Map是"key-value键值对"接口,Dictionary是声明了操做"键值对"函数接口的抽象类。算法

  • Hashtable是经过"拉链法"实现的哈希表。它包括几个重要的成员变量:table, count, threshold, loadFactor, modCount。数组

  • table是一个Entry[]数组类型,而Entry实际上就是一个单向链表。哈希表的"key-value键值对"都是存储在Entry数组中的。安全

  • count是Hashtable的大小,它是Hashtable保存的键值对的数量。函数

  • threshold是Hashtable的阈值,用于判断是否须要调整Hashtable的容量。threshold的值="容量*加载因子"。性能

  • loadFactor就是加载因子。this

  • modCount是用来实现fail-fast机制的线程

以上参考 http://www.cnblogs.com/skywang12345/p/3310887.htmlcode

Hashtable源码解析

hashtable 初始化

  • public Hashtable(int initialCapacity, float loadFactor): 用指定初始容量和指定加载因子构造一个新的空哈希表。useAltHashing 为 boolean,其若是为真,则执行另外一散列的字符串键,以减小因为弱哈希计算致使的哈希冲突的发生。

  • public Hashtable(int initialCapacity):用指定初始容量和默认的加载因子 (0.75) 构造一个新的空哈希表。

  • public Hashtable():默认构造函数,容量为 11,加载因子为 0.75。

  • public Hashtable(Map<? extends K, ? extends V> t):构造一个与给定的 Map 具备相同映射关系的新哈希表。

public Hashtable() {
    this(11, 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;
    //private transient Entry<K,V>[] table;
    table = new Entry[initialCapacity];
    // private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
    //获取阈值大小
    threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
    //初始化哈希掩码值。
    initHashSeedAsNeeded(initialCapacity);
}

private static class Entry<K,V> implements Map.Entry<K,V> {
    int hash;
    final K key;
    V value;
    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<>(hash, key, value,
                              (next==null ? null : (Entry<K,V>) next.clone()));
    }

    // Map.Entry Ops

    public K getKey() {
        return key;
    }

    public V getValue() {
        return value;
    }

    public V setValue(V value) {
        if (value == null)
            throw new NullPointerException();

        V oldValue = this.value;
        this.value = value;
        return oldValue;
    }

    public boolean equals(Object o) {
        if (!(o instanceof Map.Entry))
            return false;
        Map.Entry<?,?> e = (Map.Entry)o;

        return key.equals(e.getKey()) && value.equals(e.getValue());
    }

    public int hashCode() {
        return (Objects.hashCode(key) ^ Objects.hashCode(value));
    }

    public String toString() {
        return key.toString()+"="+value.toString();
    }
}

put方法

public synchronized V put(K key, V value) {
    // Make sure the value is not null
    if (value == null) {
        throw new NullPointerException();
    }

    // Makes sure the key is not already in the hashtable.
    //确保key不在hashtable中
    //首先,经过hash方法计算key的哈希值,并计算得出index值,肯定其在table[]中的位置
    //其次,迭代index索引位置的链表,若是该位置处的链表存在相同的key,则替换value,返回旧的value
    Entry tab[] = table;
    int hash = hash(key);
    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;
        }
    }

    modCount++;
    if (count >= threshold) {
        // Rehash the table if the threshold is exceeded
        rehash();

        tab = table;
        hash = hash(key);
        index = (hash & 0x7FFFFFFF) % tab.length;
    }

    // Creates the new entry.
    Entry<K,V> e = tab[index];
    // 建立新的Entry节点,并将新的Entry插入Hashtable的index位置,并设置e为新的Entry的下一个元素
    tab[index] = new Entry<>(hash, key, value, e);
    count++;
    return null;
}

get方法

相比较于 put 方法,get 方法则简单不少。其过程就是首先经过 hash()方法求得 key 的哈希值,而后根据 hash 值获得 index 索引(上述两步所用的算法与 put 方法都相同)。而后迭代链表,返回匹配的 key 的对应的 value;找不到则返回 null。

public synchronized V get(Object key) {
        Entry tab[] = table;
        int hash = hash(key);
        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)) {
                return e.value;
            }
        }
        return null;
    }

isEmpty方法

public synchronized boolean isEmpty() {
        return count == 0;
    }

clear方法

public synchronized void clear方法() {
    Entry tab[] = table;
    modCount++;
    for (int index = tab.length; --index >= 0; )
        tab[index] = null;
    count = 0;
}

contains和containsValue 方法

public boolean containsValue(Object value) {
	return contains(value);
}
public synchronized boolean contains(Object value) {
    if (value == null) {
        throw new NullPointerException();
    }
	//先遍历数组,在遍历数组节点
    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;
}

containsKey方法

public synchronized boolean containsKey(Object key) {
    Entry tab[] = table;
    int hash = hash(key);
    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)) {
            return true;
        }
    }
    return false;
}

Hashtable 遍历方式

package basic;

import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;

/**
 * @program: demo
 * @description: demo
 * @author: lee
 * @create: 2018-09-10
 **/
public class Demo {
    public static void main(String[] args) {
        Hashtable hashtable = new Hashtable();
        hashtable.put("123",31231);
        hashtable.put("1423",32);
        Enumeration<String> stringEnumeration = hashtable.keys();
        while (stringEnumeration.hasMoreElements()){
            String key=stringEnumeration.nextElement();
            System.out.println(hashtable.get(key));
        }
        Iterator iterator = hashtable.keySet().iterator();
        while (iterator.hasNext()) {
            Object key = iterator.next();
            System.out.println(hashtable.get(key));
        }

        Iterator iterator1 = hashtable.entrySet().iterator();

        while (iterator1.hasNext()) {
            Map.Entry entry = (Map.Entry) iterator1.next();

            System.out.println(entry.getKey());
            System.out.println(entry.getValue());
        }
    }
}

输出结果

32
31231
32
31231
1423
32
123
31231
相关文章
相关标签/搜索