java_集合体系之Hashtable详解、源码及示例——10

来源:互联网 发布:12306手机订票软件 编辑:程序博客网 时间:2024/06/10 15:16

java_集合体系之Hashtable详解、源码及示例——10

 

一:Hashtable结构图

 

 

 

简单说明:

        1、上图中虚线且无依赖字样、说明是直接实现的接口

        2、虚线但是有依赖字样、说明此类依赖与接口、但不是直接实现接口

        3、实线是继承关系、类继承类、接口继承接口

        4、实现Serielazable接口、允许使用ObjectInputStream/ObjectOutputStream读取/写入

        5、实现Map接口、以键值对形式存储数据

        6、实现Cloneable接口、允许克隆Hashtable

        7、继承Dictionary、说明Hashtable是键值对形式类、并且键、值都不允许为null。

        8、Dictionary依赖Enumeration、Hashtable可以使用Enumeration、Iterator迭代其中元素。


二:Hashtable类简介:

        1、  基于哈希表的Map结构的实现

        2、线程安全

        3、内部映射无序

        4、不允许值为null的key和value

 

三:Hashtable API


        1、构造方法

 

// 默认构造函数。public Hashtable() // 指定“容量大小”的构造函数public Hashtable(int initialCapacity) // 指定“容量大小”和“加载因子”的构造函数public Hashtable(int initialCapacity, float loadFactor) // 包含“子Map”的构造函数public Hashtable(Map<? extends K, ? extends V> t)


        2、一般方法

 

synchronized void                clear()synchronized Object              clone()             boolean             contains(Object value)synchronized boolean             containsKey(Object key)synchronized boolean             containsValue(Object value)synchronized Enumeration<V>      elements()synchronized Set<Entry<K, V>>    entrySet()synchronized boolean             equals(Object object)synchronized V                   get(Object key)synchronized int                 hashCode()synchronized boolean             isEmpty()synchronized Set<K>              keySet()synchronized Enumeration<K>      keys()synchronized V                   put(K key, V value)synchronized void                putAll(Map<? extends K, ? extends V> map)synchronized V                   remove(Object key)synchronized int                 size()synchronized String              toString()synchronized Collection<V>       values()


四:Hashtable 源码分析


说明:

        1、对哈希表要有简单的认识、

        2、Hashtable是通过“拉链法”解决哈希冲突的

        3、理解Hashtable源码中的关键部分、Entry实体类的行为、属性。Entry的存储方式、Hashtable的扩容方式、Hashtable内部关于获取新的hash code的算法。

        4、与遍历相关:可以使用Enumeration、也可以使用Iterator。

        5、与容量有关的内容Hashtable的实例有两个参数影响其性能:初始容量加载因子容量是哈希表中桶的数量,初始容量只是哈希表在创建时的容量。加载因子是哈希表在其容量自动增加之前可以达到多满的一种尺度。当哈希表中的条目数超出了加载因子与当前容量的乘积时,则要对该哈希表进行rehash 操作(即重建内部数据结构),从而哈希表将具有大约两倍的桶数。

        6、默认加载因子 (0.75) 在时间和空间成本上寻求一种折衷。加载因子过高虽然减少了空间开销,但同时也增加了查询成本(在大多数Hashtable 类的操作中,包括getput 操作,都反映了这一点)。初始容量主要控制空间消耗与执行 rehash 操作所需要的时间损耗之间的平衡。如果初始容量大于Hashtable 所包含的最大条目数除以加载因子,则永远不会发生 rehash 操作。但是,将初始容量设置太高可能会浪费空间。

        7、如果迭代性能很重要,则不要将初始容量设置得太高(或将加载因子设置得太低)。

        8、如果很多映射关系要存储在 Hashtable 实例中,则相对于按需执行自动的 rehash 操作以增大表的容量来说,使用足够大的初始容量创建它将使得映射关系能更有效地存储。

 

总结 :

        1、数据结构:Hashtable是以哈希表的形式存储数据的、并且是通过“拉链法”解决冲突、Hashtable中存储的Entry继承Map.Entry<K,V>即实现了getKey() getValue() setValue() equals() hashCode()方法、关于Hashtable存储元素的结构

 /** Hashtable中表示节点的实体类、本质是一个单向链表*/    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;}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();}    }


        2、通过Key的哈希值定位索引的算法:

// 计算索引值, % tab.length 的目的是防止数据越界int hash = key.hashCode();int index = (hash & 0x7FFFFFFF) % tab.length;

 

        3、遍历:

 

                a)Enumerator实现了Enumeration和Iterator接口、说明Enumerator同时具有使用Enumeration迭代和使用Iterator迭代功能、

 

private class Enumerator<T> implements Enumeration<T>, Iterator<T> {    //指向当前Hashtable的tableEntry[] table = Hashtable.this.table;int index = table.length;Entry<K,V> entry = null;Entry<K,V> lastReturned = null;int type;/**Enumerator是迭代器还是Enumeration的标志、true——Iterator、false——Enumeration*/boolean iterator;/** 将Enumerator当作Iterator使用时需要用到的标志fail-fast机制*/protected int expectedModCount = modCount;Enumerator(int type, boolean iterator) {    this.type = type;    this.iterator = iterator;}// 从table末尾向前查找,直到找到不为null的Entry。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方式判断是否有下一个元素public boolean hasNext() {    return hasMoreElements();}//Iterator方式获取下一个元素、多一步fail-fast验证public T next() {    if (modCount != expectedModCount)throw new ConcurrentModificationException();    return nextElement();}/** * 仅用于Iterator方式中的删除当前元素、通过计算最后一个返回的元素的hash值 * 定位到table中对应的元素、删除。 */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;else    prev.next = e.next;count--;lastReturned = null;return;    }}throw new ConcurrentModificationException();    }}    }

                b)使用Enumeration迭代时、获取Enumeration过程

                        (1)通过keys枚举:


                             



                       (2)通过elements枚举


                           



                c)使用Iterator迭代


                       (1)通过keySet()获取Set<K>的Iterator


                           



                      (2) 通过values()获取Collection<K>的Iterator


                           



                       (3)通过entrySet()获取Set<Map.Entry<K,V>>的Iterator


                            


           4、rehash():当使用Hashtable对外提供的put()方法时、put()方法内部会检测容量是否大于等于阀值、是的话调用rehash()、重构。

    /** 调整Hashtable的长度,将长度变成原来的(2倍+1)     *  1、使用临时变量记录原来table中值     *  2、创建一个新的容量为原来table容量*2 + 1 的table     *  3、将原来table中值重新赋给新table     */    protected void rehash() {int oldCapacity = table.length;Entry[] oldMap = table;int newCapacity = oldCapacity * 2 + 1;Entry[] newMap = new Entry[newCapacity];modCount++;threshold = (int)(newCapacity * loadFactor);table = newMap;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;    }}    }

    /** 将键值对存入Hashtable、不允许value为null*/    public synchronized V put(K key, V value) {// Make sure the value is not nullif (value == null) {    throw new NullPointerException();}// 如果存在相同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中不存在键为key的键值对”//修改Hashtable结构变动次数modCount++;//如果Hashtable中键值对总数大于等于阀值、则rehash()、即将容量扩增2倍+1if (count >= threshold) {    // Rehash the table if the threshold is exceeded    rehash();            tab = table;            index = (hash & 0x7FFFFFFF) % tab.length;}// 将“Hashtable中index”位置的Entry(链表)保存到e中Entry<K,V> e = tab[index];//创建新的Entry节点,并将新的Entry插入Hashtable的index位置,并设置e为新的Entry的下一个元素。    tab[index] = new Entry<K,V>(hash, key, value, e);//容量+1count++;return null;    }


五:Hashtable 示例


        1、遍历方式:

                a)通过keys获取枚举类型对象遍历:

Enumeration<String> e = hashtable.keys();

                b)通过elements获取枚举类型对象对象遍历:

Enumeration<String> e = hashtable.elements();

                c)通过keySet获取Set类型对象的Iterator遍历:

Set<String> keySet = hashtable.keySet();Iterator<String> it = keySet.iterator();

               d)通过values获取Collection类型对象的Iterator遍历:

Collection<String> values = hashtable.values();Iterator<String> it = values.iterator();

                e)通过entrySet获取Set类型对象的Iterator遍历:

Set<Entry<String, String>> entrySet = hashtable.entrySet();Iterator<Entry<String, String>> it = entrySet.iterator();

        2、迭代示例:

package com.chy.collection.example;import java.util.Collection;import java.util.Enumeration;import java.util.Hashtable;import java.util.Iterator;import java.util.Set;import java.util.Map.Entry;public class EragodicHashtable {//初始化Hashtableprivate static Hashtable<String, String> hashtable = new Hashtable<String, String>();static{for (int i = 0; i < 10; i++) {hashtable.put(""+i, ""+i);}}/** * 测试使用keys获取Enumeration遍历 */private static void testKeys(){Enumeration<String> e = hashtable.keys();while(e.hasMoreElements()){System.out.println("hash table k :" + e.nextElement());}System.out.println("==============================================");}/** * 测试使用elements获取Enumeration遍历 */private static void testElements(){Enumeration<String> e = hashtable.elements();while(e.hasMoreElements()){System.out.println("hash table vlaue :" + e.nextElement());}System.out.println("==============================================");}/** * 测试使用keySet获取Set<K>的Iterator遍历 */private static void testKeySet(){Set<String> keySet = hashtable.keySet();Iterator<String> it = keySet.iterator();while(it.hasNext()){System.out.println("hash table k : " + it.next());}System.out.println("==============================================");}/** * 测试使用values获取Collection<V>的Iterator遍历 */private static void testValues(){Collection<String> values = hashtable.values();Iterator<String> it = values.iterator();while(it.hasNext()){System.out.println("hash table value : " + it.next());}System.out.println("==============================================");}/** * 测试使用entrySet<Map.Entry<K, V>>的Iterator遍历 */private static void testEntrySet(){Set<Entry<String, String>> entrySet = hashtable.entrySet();Iterator<Entry<String, String>> it = entrySet.iterator();while(it.hasNext()){System.out.println("hash table entry : " + it.next());}System.out.println("==============================================");}public static void main(String[] args) {testKeys();testElements();testKeySet();testValues();testEntrySet();}}

        3、API示例:

package com.chy.collection.example;import java.util.HashMap;import java.util.Hashtable;@SuppressWarnings("all")public class HashtableTest {/** * 测试构造方法、下面四个方法效果相同、 */private static void testConstructor(){//use default constructHashtable<String, String> ht1 = new Hashtable<String, String>();//use specified initCapacityHashtable<String, String> ht2 = new Hashtable<String, String>(11);//use specified initCapacity and loadFactorHashtable<String, String> ht3 = new Hashtable<String, String>(11, 0.75f);//use specified MapHashtable<String, String> ht4 = new Hashtable<String, String>(ht1);}/** * 测试API方法 */public static void main(String[] args) {//初始化、键-值都为字符串"1"的hashMapHashtable<String, String> ht = new Hashtable<String, String>();for (int i = 0; i < 10; i++) {ht.put(""+i, ""+i);}/* * 向Hashtable中添加键为null的键值对 * 只会在Hashtable的index为0处、保存一个键为null的键值对、键为null、值为最后一次添加的键值对的值。 */ht.put(null, null);ht.put(null, "n");System.out.println(ht.size());System.out.println(ht);//是否包含键“1”System.out.println("Hashtable contans key ? " + ht.containsKey("1"));//是否包含值“1”System.out.println("Hashtable contans value ? " + ht.containsValue("1"));//获取键为“1”的值System.out.println("the value of key=1 " + ht.get("1"));//将键为“1”的值修改成"11"ht.put("1", "11");//将Hashtable复制到Hashtable1中Hashtable<String, String> Hashtable1 = (Hashtable<String, String>)ht.clone();//将Hashtable1所有键值对复制到Hashtable中ht.putAll(Hashtable1);System.out.println(ht);//不会有二十个元素、因为他不会再添加重复元素//如果Hashtable非空、则清空 if(!ht.isEmpty()){ht.clear();}System.out.println(ht.size());}}


更多内容:java_集合体系之总体目录——00



3 0
原创粉丝点击