和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
// 默认构造函数。 public Hashtable() // 指定“容量大小”的构造函数 public Hashtable(int initialCapacity) // 指定“容量大小”和“加载因子”的构造函数 public Hashtable(int initialCapacity, float loadFactor) // 包含“子Map”的构造函数 public Hashtable(Map<? extends K, ? extends V> t)
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机制的线程
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(); } }
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; }
相比较于 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; }
public synchronized boolean isEmpty() { return count == 0; }
public synchronized void clear方法() { Entry tab[] = table; modCount++; for (int index = tab.length; --index >= 0; ) tab[index] = null; count = 0; }
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; }
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; }
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