Hashtable源码分析

来源:互联网 发布:mysql从零开始学 编辑:程序博客网 时间:2024/05/18 00:49

1.概述

      Hashtable实现了一个Hash表,并由此将键(Key)映射为与之相对应的值(Value)。任何非null的对象都可以作为该Hash表的键或者值。为了能够实现在Hash表中存储和获取对象,用作键的对象必须实现hashCode方法和equals方法。Hashtable的抽象父类Dictionary定义了对Hash表操作的基本方法:

    abstract public int size();    abstract public boolean isEmpty();    abstract public Enumeration<K> keys();    abstract public Enumeration<V> elements();    abstract public V get(Object key);    abstract public V put(K key, V value);    abstract public V remove(Object key);

但在JDK1.2之后Dictionary就再见了,如果需要实现Hash表则不再使用继承Dictionary的方式,转而采用实现Map接口的方式。Hashtable也被改进以实现Map接口,使之和Java Collections Framework的整体设计相同,但与新的实现不同之处在于,Hashtable是同步的,感觉这好像也是Hashtable仍没有被彻底丢弃的唯一能说的过去的理由了(虽然几乎没有怎么见到过用Hashtable),因为貌似其他的区别之处大部分都是因为历史遗留原因了。

2.快速失败

      在JDK的文档中很多与Collection迭代相关的部分都提到了快速失败(fail-fast),其主要是针对非并发集合(HashMap,Hashtable),在对非并发集合进行迭代时,collection的iterator返回的迭代器是快速失败的,即在创建了Iterator之后,如果从结构上对collection进行修改(增减),除非通过Iterator自身的remove方法,否则在任何时间任何方式对其进行修改都会抛出ConcurrentModificationException。就是说面对并发的修改Iterator很快就会完全失败或者说是立即抛出异常,而不是等到迭代完成或在某个不确定的时间点出现错误时才让你知道,就是说不冒任何风险。

      Hashtable 的键和元素方法返回的 Enumeration 不是快速失败的

3.拉链法

         拉链法解决冲突的做法是:将所有关键字为同义词的结点链接在同一个单链表中。若选定的散列表长度为m,则可将散列表定义为一个由m个头指针组成的指针数组T[0..m-1]。凡是散列地址为i的结点,均插入到以T[i]为头指针的单链表中。T中各分量的初值均应为空指针。在拉链法中,装填因子α可以大于1,但一般均取α≤1。

4.源码注释

public class Hashtable<K, V> extends Dictionary<K, V> implements Map<K, V>,Cloneable, java.io.Serializable {/* * Hashtable保存的是key-value的数组Hashtbale是采用拉链法实现的,每一个Entry本质上是一个单向链表 * 拉链法的本质:当散列表冲突时 ,我们重开一条链表。transient 序列化时忽略该字段。 * 数组存放的是实体的引用,序列化时必须遍历该字段逐个实体序列化。 */private transient Entry[] table;//Hashtable的容量大小private transient int count;//Hashtable的门限值,用于判断是否对Hashtable扩容private int threshold;//加载因子=容量*加载因子private float loadFactor;//Hashtable被改变次数的计数器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);//如果容量==1,将其置为1if (initialCapacity == 0)initialCapacity = 1;//初始化加载因子、存储的数组、门限值this.loadFactor = loadFactor;table = new Entry[initialCapacity];threshold = (int) (initialCapacity * loadFactor);}//带有默认加载因子的构造函数public Hashtable(int initialCapacity) {this(initialCapacity, 0.75f);}//带有默认容量与加载因子的构造函数,容量默认11,加载因子0.75public Hashtable() {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);}//返回Hashtable的大小public synchronized int size() {return count;}//判断Hashtable是否为空public synchronized boolean isEmpty() {return count == 0;}//返回Hashtable中所有键key的枚举对象public synchronized Enumeration<K> keys() {return this.<K> getEnumeration(KEYS);}//返回Hashtable中所有值value的枚举对象public synchronized Enumeration<V> elements() {return this.<V> getEnumeration(VALUES);}/* * 判断某个值是否存在于该Hashtable中,其中table = new * Entry[initialCapacity],是Hashtable的存储数组,当出现碰撞时则以链表的形式进行存储, * 所以在测试此映射表中是否存在与指定值关联的键时需要对整个Hashtable进行遍历,直到找到为止。 */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;}//判断某个值是否存在于该Hashtable中,实现Map接口public boolean containsValue(Object value) {return contains(value);}/* * 测试指定对象是否为此哈希表中的键,可以看到在Hashtable中使用的hashcode为该对象原有的hashcode的值, hash & * 0x7FFFFFFF是一个比较常见的将hashcode限制到31位的方法,对该对象是该Hashtable的键时返回true */public synchronized boolean containsKey(Object key) {Entry tab[] = table;int hash = key.hashCode();// 取得该hashcode对应的index值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;}/* * 返回指定键所映射到的值,如果此映射不包含此键的映射,则返回 null,实现方法与containsKey相同, * 只是在返回时返回该键对应的值或者返回null。 */public synchronized V get(Object key) {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)) {return e.value;}}return null;}/* * 当Hashtable中的键的数量超出哈希表的容量和加载因子时,自动调用该方法,增加Hashtable的容量, 并对该Hashtable进行重组。 */protected void rehash() {int oldCapacity = table.length;Entry[] oldMap = table;// 新容量是旧容量的大小*2+1,默认初始容量大小是11。int newCapacity = oldCapacity * 2 + 1;Entry[] newMap = new Entry[newCapacity];// 用来记录Hashtable在结构上被修改的次数modCount++;// 设定新的门限值容量*0.75(默认)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;int index = (e.hash & 0x7FFFFFFF) % newCapacity;e.next = newMap[index];newMap[index] = e;}}}/* * 根据所给定的键key,将其对应的值映射到Hashtable中的对应位置。 */public synchronized V put(K key, V value) {// 如果值为空则抛出NullPointerExceptionif (value == null) {throw new NullPointerException();}// 根据key计算其对应的映射位置,并判断在Hashtable中是否存在该键key,如果存在则更新相应的值value,并返回原有的值valueEntry 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的修改记录+1modCount++;// 如果该Hashtable的存储容量已经大于或者等于门限值,则对其进行rehash操作,并重新计算本次需要put的键key的indexif (count >= threshold) {// Rehash the table if the threshold is exceededrehash();tab = table;index = (hash & 0x7FFFFFFF) % tab.length;}// 将Hashtable中index位置的Entry(链表)保存到e中Entry<K, V> e = tab[index];// 将新的Entry放在链表最前并存在index位置tab[index] = new Entry<K, V>(hash, key, value, e);// 容量+1count++;return null;}//删除给定键key对象对应的元素(键与值)public synchronized V remove(Object key) {Entry tab[] = table;int hash = key.hashCode();//计算indexint index = (hash & 0x7FFFFFFF) % tab.length;//遍历查找对应的链表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;}//将map里的键与值全部存入Hashtable中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());}//清空Hashtablepublic synchronized void clear() {Entry tab[] = table;modCount++;for (int index = tab.length; --index >= 0;)tab[index] = null;count = 0;}//clone该Hashtable,以Object形式返回。public synchronized Object clone() {try {Hashtable<K, V> t = (Hashtable<K, V>) super.clone();t.table = new Entry[table.length];for (int i = table.length; i-- > 0;) {t.table[i] = (table[i] != null) ? (Entry<K, V>) table[i].clone() : null;}t.keySet = null;t.entrySet = null;t.values = null;t.modCount = 0;return t;} catch (CloneNotSupportedException e) {// this shouldn't happen, since we are Cloneablethrow new InternalError();}}//重写toString方法public synchronized String toString() {int max = size() - 1;if (max == -1)return "{}";StringBuilder sb = new StringBuilder();Iterator<Map.Entry<K, V>> it = entrySet().iterator();sb.append('{');for (int i = 0;; i++) {Map.Entry<K, V> e = it.next();K key = e.getKey();V value = e.getValue();sb.append(key == this ? "(this Map)" : key.toString());sb.append('=');sb.append(value == this ? "(this Map)" : value.toString());if (i == max)return sb.append('}').toString();sb.append(", ");}}//获取Hashtable的枚举对象,如果Hashtable为空则返回空枚举对象private <T> Enumeration<T> getEnumeration(int type) {if (count == 0) {return (Enumeration<T>) emptyEnumerator;} else {return new Enumerator<T>(type, false);}}//获取Hashtable的Iterator对象,如果Hashtable为空则返回空Iterator对象private <T> Iterator<T> getIterator(int type) {if (count == 0) {return (Iterator<T>) emptyIterator;} else {return new Enumerator<T>(type, true);}}//Hashtable的key集合,使用set存储,不存在重复keyprivate transient volatile Set<K> keySet = null;//Hashtable的key-value键值对集合,使用set存储,不存在重复元素private transient volatile Set<Map.Entry<K, V>> entrySet = null;//Hashtable的value集合,使用Collection存储,可以重复private transient volatile Collection<V> values = null;/* * 使用Collections.synchronizedSet返回一个synchronized的keySet对象,以实现对线程同步, * synchronizedSet对keySet的所有方法都添加synchronized */public Set<K> keySet() {if (keySet == null)keySet = Collections.synchronizedSet(new KeySet(), this);return keySet;}//Hashtable的key集合,继承自AbstractSetprivate class KeySet extends AbstractSet<K> {public Iterator<K> iterator() {return getIterator(KEYS);}public int size() {return count;}public boolean contains(Object o) {return containsKey(o);}public boolean remove(Object o) {return Hashtable.this.remove(o) != null;}public void clear() {Hashtable.this.clear();}}/* * 使用Collections.synchronizedSet返回一个synchronized的entrySet对象,以实现对线程同步, * synchronizedSet对entrySet的所有方法都添加synchronized */public Set<Map.Entry<K, V>> entrySet() {if (entrySet == null)entrySet = Collections.synchronizedSet(new EntrySet(), this);return entrySet;}//Hashtable的key-value键值对集合,继承自AbstractSet,其中键值对形式的元素不会重复private class EntrySet extends AbstractSet<Map.Entry<K, V>> {public Iterator<Map.Entry<K, V>> iterator() {return getIterator(ENTRIES);}public boolean add(Map.Entry<K, V> o) {return super.add(o);}public boolean contains(Object o) {if (!(o instanceof Map.Entry))return false;Map.Entry entry = (Map.Entry) o;Object key = entry.getKey();Entry[] tab = table;int hash = key.hashCode();int index = (hash & 0x7FFFFFFF) % tab.length;for (Entry e = tab[index]; e != null; e = e.next)if (e.hash == hash && e.equals(entry))return true;return false;}public boolean remove(Object o) {if (!(o instanceof Map.Entry))return false;Map.Entry<K, V> entry = (Map.Entry<K, V>) o;K key = entry.getKey();Entry[] tab = table;int hash = key.hashCode();int index = (hash & 0x7FFFFFFF) % tab.length;for (Entry<K, V> e = tab[index], prev = null; e != null; prev = e, e = e.next) {if (e.hash == hash && e.equals(entry)) {modCount++;if (prev != null)prev.next = e.next;elsetab[index] = e.next;count--;e.value = null;return true;}}return false;}public int size() {return count;}public void clear() {Hashtable.this.clear();}}/* * 使用Collections.synchronizedSet返回一个synchronized的values对象,以实现对线程同步, * synchronizedSet对values的所有方法都添加synchronized */public Collection<V> values() {if (values == null)values = Collections.synchronizedCollection(new ValueCollection(),this);return values;}//Hashtable的values集合,继承自AbstractCollectionprivate class ValueCollection extends AbstractCollection<V> {public Iterator<V> iterator() {return getIterator(VALUES);}public int size() {return count;}public boolean contains(Object o) {return containsValue(o);}public void clear() {Hashtable.this.clear();}}//重写equals方法,如果两个Hashtable的所有key-value元素都相等则认为两个Hashtable相等public synchronized boolean equals(Object o) {if (o == this)return true;if (!(o instanceof Map))return false;Map<K, V> t = (Map<K, V>) o;if (t.size() != size())return false;//从Hashtable中遍历,判断每一个key是否在与之比较的Hashtable中存在,并且是否value也相等try {Iterator<Map.Entry<K, V>> i = entrySet().iterator();while (i.hasNext()) {Map.Entry<K, V> e = i.next();K key = e.getKey();V value = e.getValue();if (value == null) {if (!(t.get(key) == null && t.containsKey(key)))return false;} else {if (!value.equals(t.get(key)))return false;}}} catch (ClassCastException unused) {return false;} catch (NullPointerException unused) {return false;}return true;}//重写hashCode方法public synchronized int hashCode() {int h = 0;//如果Hashtable大小为0,或者加载因子小于0,返回0if (count == 0 || loadFactor < 0)return h; // Returns zeroloadFactor = -loadFactor; // Mark hashCode computation in progressEntry[] tab = table;//返回Hashtable中的每个Entry的key和value的异或值 的总和for (int i = 0; i < tab.length; i++)for (Entry e = tab[i]; e != null; e = e.next)h += e.key.hashCode() ^ e.value.hashCode();loadFactor = -loadFactor; // Mark hashCode computation completereturn h;}//java.io.Serializable的写入方法private synchronized void writeObject(java.io.ObjectOutputStream s)throws IOException {// Write out the length, threshold, loadfactors.defaultWriteObject();// Write out length, count of elements and then the key/value objects//写入Hashtable的总容量s.writeInt(table.length);//写入Hashtable的实际大小s.writeInt(count);//写入所有的Entryfor (int index = table.length - 1; index >= 0; index--) {Entry entry = table[index];while (entry != null) {s.writeObject(entry.key);s.writeObject(entry.value);entry = entry.next;}}}//java.io.Serializable的读取函数:根据写入方式读出private void readObject(java.io.ObjectInputStream s) throws IOException,ClassNotFoundException {// Read in the length, threshold, and loadfactors.defaultReadObject();// Read the original length of the array and number of elements//读入总容量int origlength = s.readInt();//读入实际大小int elements = s.readInt();// Compute new size with a bit of room 5% to grow but// no larger than the original size. Make the length// odd if it's large enough, this helps distribute the entries.// Guard against the length ending up zero, that's not valid.int length = (int) (elements * loadFactor) + (elements / 20) + 3;if (length > elements && (length & 1) == 0)length--;if (origlength > 0 && length > origlength)length = origlength;Entry[] table = new Entry[length];count = 0;// Read the number of elements and then all the key/value objectsfor (; elements > 0; elements--) {K key = (K) s.readObject();V value = (V) s.readObject();// synch could be eliminated for performancereconstitutionPut(table, key, value);}this.table = table;}//重建Entry[]数组,主要是供readObject方法使用private void reconstitutionPut(Entry[] tab, K key, V value)throws StreamCorruptedException {if (value == null) {throw new java.io.StreamCorruptedException();}// Makes sure the key is not already in the hashtable.// This should not happen in deserialized version.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)) {throw new java.io.StreamCorruptedException();}}// Creates the new entry.Entry<K, V> e = tab[index];tab[index] = new Entry<K, V>(hash, key, value, e);count++;}//Entry元素类,其实质上是一个单链表private static class Entry<K, V> implements Map.Entry<K, V> {int hash;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<K, V>(hash, key, value, (next == null ? null: (Entry<K, V>) next.clone()));}// Map.Entry Opspublic 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;}//重写equals方法,如果两个元素的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();}}// Types of Enumerations/Iterationsprivate static final int KEYS = 0;private static final int VALUES = 1;private static final int ENTRIES = 2;//Hashtable的枚举器类,实现了Enumeration与Iterator接口private class Enumerator<T> implements Enumeration<T>, Iterator<T> {Entry[] table = Hashtable.this.table;int index = table.length;Entry<K, V> entry = null;Entry<K, V> lastReturned = null;int type;//指明该枚举是迭代器还是枚举,当为true是为迭代器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. *///当该枚举器为iterator形式时用来判断其修改状态,用以实现快速失败机制protected int expectedModCount = modCount;Enumerator(int type, boolean iterator) {this.type = type;this.iterator = iterator;}//遍历Hashtable,以遍历是否结束作为返回值,遍历方式为从数组末尾向前public boolean hasMoreElements() {Entry<K, V> e = entry;int i = index;Entry[] t = table;/* Use locals for faster loop iteration */while (e == null && i > 0) {e = t[--i];}entry = e;index = i;return e != null;}//获取下一个元素,遍历方式为从数组末尾向前,链表由表头到表尾(?)public T nextElement() {Entry<K, V> et = entry;int i = index;Entry[] t = table;/* Use locals for faster loop iteration */while (et == null && i > 0) {et = t[--i];}entry = et;index = i;if (et != null) {Entry<K, V> e = lastReturned = entry;entry = e.next;return type == KEYS ? (T) e.key : (type == VALUES ? (T) e.value: (T) e);}throw new NoSuchElementException("Hashtable Enumerator");}// Iterator methodspublic boolean hasNext() {return hasMoreElements();}public T next() {if (modCount != expectedModCount)throw new ConcurrentModificationException();return nextElement();}//迭代器的删除方法,对该Hashtable同步后删除对应的元素public void remove() {if (!iterator)throw new UnsupportedOperationException();if (lastReturned == null)throw new IllegalStateException("Hashtable Enumerator");if (modCount != expectedModCount)throw new ConcurrentModificationException();synchronized (Hashtable.this) {Entry[] tab = Hashtable.this.table;int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length;for (Entry<K, V> e = tab[index], prev = null; e != null; prev = e, e = e.next) {if (e == lastReturned) {modCount++;expectedModCount++;if (prev == null)tab[index] = e.next;elseprev.next = e.next;count--;lastReturned = null;return;}}throw new ConcurrentModificationException();}}}private static Enumeration emptyEnumerator = new EmptyEnumerator();private static Iterator emptyIterator = new EmptyIterator();//空枚举器,当Hashtable为空时返回该枚举器private static class EmptyEnumerator implements Enumeration<Object> {EmptyEnumerator() {}public boolean hasMoreElements() {return false;}public Object nextElement() {throw new NoSuchElementException("Hashtable Enumerator");}}//空迭代器,当Hashtable为空时返回该迭代器private static class EmptyIterator implements Iterator<Object> {EmptyIterator() {}public boolean hasNext() {return false;}public Object next() {throw new NoSuchElementException("Hashtable Iterator");}public void remove() {throw new IllegalStateException("Hashtable Iterator");}}}






0 0
原创粉丝点击