zoukankan      html  css  js  c++  java
  • HashTable的实现原理

    一、---使用方式---

    (1)Hashtable 是一个散列表,它存储的内容是键值对(key-value)映射。

    (2)Hashtable 继承于Dictionary,实现了Map、Cloneable、java.io.Serializable接口。

    (3)Hashtable 的函数都是同步的,这意味着它是线程安全的。它的key、value都不可以为null。

    如下是Hashtable 的简单使用方式:在遍历时使用是三种遍历方式来对其进行遍历

    package ThreeWeek;  
      
    import java.util.Enumeration;  
    import java.util.Hashtable;  
    import java.util.Iterator;  
    import java.util.Map;  
    import java.util.Map.Entry;  
      
    public class HashTableTest {  
      
        public static void main(String args[]){  
            Hashtable<String, Integer> table = new Hashtable<String, Integer>();  
              
            //[1]添加元素  
            table.put("zhangsan", 22);  
            table.put("lisi", 33);  
            table.put("wangwu", 44);  
              
            //[2]toString()方式打印  
            System.out.println(table.toString());  
              
            //[3]Iterator遍历方式1--键值对遍历entrySet()  
            Iterator<Entry<String, Integer>> iter = table.entrySet().iterator();  
            while(iter.hasNext()){  
                Map.Entry<String, Integer> entry = (Map.Entry<String, Integer>)iter.next();  
                String key = entry.getKey();  
                int value = entry.getValue();  
                System.out.println("entrySet:"+key+" "+value);  
            }  
              
            System.out.println("====================================");  
              
            //[4]Iterator遍历方式2--key键的遍历  
            Iterator<String> iterator = table.keySet().iterator();  
            while(iterator.hasNext()){  
                String key = (String)iterator.next();  
                int value = table.get(key);  
                System.out.println("keySet:"+key+" "+value);  
            }  
              
            System.out.println("====================================");  
              
            //[5]通过Enumeration来遍历Hashtable  
            Enumeration<String> enu = table.keys();  
            while(enu.hasMoreElements()) {  
                System.out.println("Enumeration:"+table.keys()+" "+enu.nextElement());  
            }   
                  
        }  
    }  
    

      

    输出:

    {zhangsan=22, lisi=33, wangwu=44}  
    entrySet:zhangsan 22  
    entrySet:lisi 33  
    entrySet:wangwu 44  
    ====================================  
    keySet:zhangsan 22  
    keySet:lisi 33  
    keySet:wangwu 44  
    ====================================  
    Enumeration:java.util.Hashtable$Enumerator@139a55 zhangsan  
    Enumeration:java.util.Hashtable$Enumerator@1db9742 lisi  
    Enumeration:java.util.Hashtable$Enumerator@106d69c wangwu  
    

      

    二、---内部原理---

    1、继承关系

    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 { }  

    与HashMap不同的是Hashtable是继承Dictionary,实现了Map接口。Map是"key-value键值对"接口,Dictionary是声明了操作"键值对"函数接口的抽象类。 

    2、构造函数

    (1)Hashtable中提供了四个构造函数,如下:

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

    (2)上面的四个构造方法中,第三个是最重要的,指定初始化容量和构造因子

    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,获得大小为initialCapacity的table数组    
            table = new Entry[initialCapacity];    
            //计算阀值    
            threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);    
            //初始化HashSeed值    
            initHashSeedAsNeeded(initialCapacity);    
        }    

    3、成员变量

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

    (2)count是Hashtable的大小,它是Hashtable保存的键值对的数量。 

    (3)threshold是Hashtable的阈值,用于判断是否需要调整Hashtable的容量。threshold的值="容量*加载因子"。

    (4)loadFactor就是加载因子。

    (5)modCount是用来实现fail-fast机制的

    private transient Entry[] table;  
    // Hashtable中元素的实际数量  
    private transient int count;  
    // 阈值,用于判断是否需要调整Hashtable的容量(threshold = 容量*加载因子)  
    private int threshold;  
    // 加载因子  
    private float loadFactor;  
    // Hashtable被改变的次数  
    private transient int modCount = 0;  

    4、put和get方法

    (1)put方法

    从下面的代码中我们可以看出,Hashtable中的key和value是不允许为空的,当我们想要想Hashtable中添加元素的时候,首先计算key的hash值,然

    后通过hash值确定在table数组中的索引位置,最后将value值替换或者插入新的元素,如果容器的数量达到阈值,就会进行扩充。

    public synchronized V put(K key, V value) {    
            // 确保value不为null    
            if (value == null) {    
                throw new NullPointerException();    
            }    
        
            /*  
             * 确保key在table[]是不重复的  
             * 处理过程:  
             * 1、计算key的hash值,确认在table[]中的索引位置  
             * 2、迭代index索引位置,如果该位置处的链表中存在一个一样的key,则替换其value,返回旧值  
             */    
            Entry tab[] = table;    
            int hash = hash(key);    //计算key的hash值    
            int index = (hash & 0x7FFFFFFF) % tab.length;     //确认该key的索引位置    
            //迭代,寻找该key,替换    
            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();    
                tab = table;    
                hash = hash(key);    
                index = (hash & 0x7FFFFFFF) % tab.length;    
            }    
        
            // 在索引位置处插入一个新的节点    
            Entry<K,V> e = tab[index];    
            tab[index] = new Entry<>(hash, key, value, e);    
            //容器中元素+1    
            count++;    
            return null;    
        }    
    

     

    (2)get方法

    同样也是先获得索引值,然后进行遍历,最后返回

    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;    
        }    
    

    、---比较不同---

    Hashtable和HashMap到底有哪些不同呢

    (1)基类不同:HashTable基于Dictionary类,而HashMap是基于AbstractMap。Dictionary是什么?它是任何可将键映射到相应值的类的抽象父类,而AbstractMap是基于Map接口的骨干实现,它以最大限度地减少实现此接口所需的工作。

    (2)null不同:HashMap可以允许存在一个为null的key和任意个为null的value,但是HashTable中的key和value都不允许为null。

    (3)线程安全:HashMap时单线程安全的,Hashtable是多线程安全的。

    (4)遍历不同:HashMap仅支持Iterator的遍历方式,Hashtable支持Iterator和Enumeration两种遍历方式。

  • 相关阅读:
    《应用Yii1.1和PHP5进行敏捷Web开发》学习笔记(转)
    YII 小模块功能
    Netbeans代码配色主题大搜集
    opensuse 启动巨慢 解决方法 90s多
    opensuse 安装 网易云音乐 rpm netease music
    linux qq rpm deb opensuse
    openSUSE 安装 alien
    第一行代码 Android 第2版
    Android Studio AVD 虚拟机 联网 失败
    docker error during connect: Get http://%2F%2F.%2Fpipe%2Fdocker_engine/v1.29/containers/json: open //./pipe/docker_engine: The system cannot find the file specified. In the default daemon configuratio
  • 原文地址:https://www.cnblogs.com/owenma/p/8554568.html
Copyright © 2011-2022 走看看