zoukankan      html  css  js  c++  java
  • Java 集合系列11之 Hashtable详细介绍(源码解析)和使用示例

    概要

    前一章,我们学习了HashMap。这一章,我们对Hashtable进行学习。
    我们先对Hashtable有个整体认识,然后再学习它的源码,最后再通过实例来学会使用Hashtable。
    第1部分 Hashtable介绍
    第2部分 Hashtable数据结构
    第3部分 Hashtable源码解析(基于JDK1.6.0_45)
    第4部分 Hashtable遍历方式
    第5部分 Hashtable示例

    转载:http://www.cnblogs.com/skywang12345/p/3310887.html

    第1部分 Hashtable介绍

    Hashtable 简介

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

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

    Hashtable的构造函数

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

    Hashtable的API

    复制代码
    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()
    复制代码

    第2部分 Hashtable数据结构

    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与Map关系如下图:

    从图中可以看出:
    (01) Hashtable继承于Dictionary类,实现了Map接口。Map是"key-value键值对"接口,Dictionary是声明了操作"键值对"函数接口的抽象类。
    (02) Hashtable是通过"拉链法"实现的哈希表。它包括几个重要的成员变量:table, count, threshold, loadFactor, modCount。
      table是一个Entry[]数组类型,而Entry实际上就是一个单向链表。哈希表的"key-value键值对"都是存储在Entry数组中的。
      count是Hashtable的大小,它是Hashtable保存的键值对的数量。
      threshold是Hashtable的阈值,用于判断是否需要调整Hashtable的容量。threshold的值="容量*加载因子"。
      loadFactor就是加载因子。
      modCount是用来实现fail-fast机制的

    第3部分 Hashtable源码解析(基于JDK1.6.0_45)

    为了更了解Hashtable的原理,下面对Hashtable源码代码作出分析。
    在阅读源码时,建议参考后面的说明来建立对Hashtable的整体认识,这样更容易理解Hashtable。

    复制代码
      1 package java.util;
      2 import java.io.*;
      3 
      4 public class Hashtable<K,V>
      5     extends Dictionary<K,V>
      6     implements Map<K,V>, Cloneable, java.io.Serializable {
      7 
      8     // Hashtable保存key-value的数组。
      9     // Hashtable是采用拉链法实现的,每一个Entry本质上是一个单向链表
     10     private transient Entry[] table;
     11 
     12     // Hashtable中元素的实际数量
     13     private transient int count;
     14 
     15     // 阈值,用于判断是否需要调整Hashtable的容量(threshold = 容量*加载因子)
     16     private int threshold;
     17 
     18     // 加载因子
     19     private float loadFactor;
     20 
     21     // Hashtable被改变的次数
     22     private transient int modCount = 0;
     23 
     24     // 序列版本号
     25     private static final long serialVersionUID = 1421746759512286392L;
     26 
     27     // 指定“容量大小”和“加载因子”的构造函数
     28     public Hashtable(int initialCapacity, float loadFactor) {
     29         if (initialCapacity < 0)
     30             throw new IllegalArgumentException("Illegal Capacity: "+
     31                                                initialCapacity);
     32         if (loadFactor <= 0 || Float.isNaN(loadFactor))
     33             throw new IllegalArgumentException("Illegal Load: "+loadFactor);
     34 
     35         if (initialCapacity==0)
     36             initialCapacity = 1;
     37         this.loadFactor = loadFactor;
     38         table = new Entry[initialCapacity];
     39         threshold = (int)(initialCapacity * loadFactor);
     40     }
     41 
     42     // 指定“容量大小”的构造函数
     43     public Hashtable(int initialCapacity) {
     44         this(initialCapacity, 0.75f);
     45     }
     46 
     47     // 默认构造函数。
     48     public Hashtable() {
     49         // 默认构造函数,指定的容量大小是11;加载因子是0.75
     50         this(11, 0.75f);
     51     }
     52 
     53     // 包含“子Map”的构造函数
     54     public Hashtable(Map<? extends K, ? extends V> t) {
     55         this(Math.max(2*t.size(), 11), 0.75f);
     56         // 将“子Map”的全部元素都添加到Hashtable中
     57         putAll(t);
     58     }
     59 
     60     public synchronized int size() {
     61         return count;
     62     }
     63 
     64     public synchronized boolean isEmpty() {
     65         return count == 0;
     66     }
     67 
     68     // 返回“所有key”的枚举对象
     69     public synchronized Enumeration<K> keys() {
     70         return this.<K>getEnumeration(KEYS);
     71     }
     72 
     73     // 返回“所有value”的枚举对象
     74     public synchronized Enumeration<V> elements() {
     75         return this.<V>getEnumeration(VALUES);
     76     }
     77 
     78     // 判断Hashtable是否包含“值(value)”
     79     public synchronized boolean contains(Object value) {
     80         // Hashtable中“键值对”的value不能是null,
     81         // 若是null的话,抛出异常!
     82         if (value == null) {
     83             throw new NullPointerException();
     84         }
     85 
     86         // 从后向前遍历table数组中的元素(Entry)
     87         // 对于每个Entry(单向链表),逐个遍历,判断节点的值是否等于value
     88         Entry tab[] = table;
     89         for (int i = tab.length ; i-- > 0 ;) {
     90             for (Entry<K,V> e = tab[i] ; e != null ; e = e.next) {
     91                 if (e.value.equals(value)) {
     92                     return true;
     93                 }
     94             }
     95         }
     96         return false;
     97     }
     98 
     99     public boolean containsValue(Object value) {
    100         return contains(value);
    101     }
    102 
    103     // 判断Hashtable是否包含key
    104     public synchronized boolean containsKey(Object key) {
    105         Entry tab[] = table;
    106         int hash = key.hashCode();
    107         // 计算索引值,
    108         // % tab.length 的目的是防止数据越界
    109         int index = (hash & 0x7FFFFFFF) % tab.length;
    110         // 找到“key对应的Entry(链表)”,然后在链表中找出“哈希值”和“键值”与key都相等的元素
    111         for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
    112             if ((e.hash == hash) && e.key.equals(key)) {
    113                 return true;
    114             }
    115         }
    116         return false;
    117     }
    118 
    119     // 返回key对应的value,没有的话返回null
    120     public synchronized V get(Object key) {
    121         Entry tab[] = table;
    122         int hash = key.hashCode();
    123         // 计算索引值,
    124         int index = (hash & 0x7FFFFFFF) % tab.length;
    125         // 找到“key对应的Entry(链表)”,然后在链表中找出“哈希值”和“键值”与key都相等的元素
    126         for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
    127             if ((e.hash == hash) && e.key.equals(key)) {
    128                 return e.value;
    129             }
    130         }
    131         return null;
    132     }
    133 
    134     // 调整Hashtable的长度,将长度变成原来的(2倍+1)
    135     // (01) 将“旧的Entry数组”赋值给一个临时变量。
    136     // (02) 创建一个“新的Entry数组”,并赋值给“旧的Entry数组”
    137     // (03) 将“Hashtable”中的全部元素依次添加到“新的Entry数组”中
    138     protected void rehash() {
    139         int oldCapacity = table.length;
    140         Entry[] oldMap = table;
    141 
    142         int newCapacity = oldCapacity * 2 + 1;
    143         Entry[] newMap = new Entry[newCapacity];
    144 
    145         modCount++;
    146         threshold = (int)(newCapacity * loadFactor);
    147         table = newMap;
    148 
    149         for (int i = oldCapacity ; i-- > 0 ;) {
    150             for (Entry<K,V> old = oldMap[i] ; old != null ; ) {
    151                 Entry<K,V> e = old;
    152                 old = old.next;
    153 
    154                 int index = (e.hash & 0x7FFFFFFF) % newCapacity;
    155                 e.next = newMap[index];
    156                 newMap[index] = e;
    157             }
    158         }
    159     }
    160 
    161     // 将“key-value”添加到Hashtable中
    162     public synchronized V put(K key, V value) {
    163         // Hashtable中不能插入value为null的元素!!!
    164         if (value == null) {
    165             throw new NullPointerException();
    166         }
    167 
    168         // 若“Hashtable中已存在键为key的键值对”,
    169         // 则用“新的value”替换“旧的value”
    170         Entry tab[] = table;
    171         int hash = key.hashCode();
    172         int index = (hash & 0x7FFFFFFF) % tab.length;
    173         for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
    174             if ((e.hash == hash) && e.key.equals(key)) {
    175                 V old = e.value;
    176                 e.value = value;
    177                 return old;
    178                 }
    179         }
    180 
    181         // 若“Hashtable中不存在键为key的键值对”,
    182         // (01) 将“修改统计数”+1
    183         modCount++;
    184         // (02) 若“Hashtable实际容量” > “阈值”(阈值=总的容量 * 加载因子)
    185         //  则调整Hashtable的大小
    186         if (count >= threshold) {
    187             // Rehash the table if the threshold is exceeded
    188             rehash();
    189 
    190             tab = table;
    191             index = (hash & 0x7FFFFFFF) % tab.length;
    192         }
    193 
    194         // (03) 将“Hashtable中index”位置的Entry(链表)保存到e中
    195         Entry<K,V> e = tab[index];
    196         // (04) 创建“新的Entry节点”,并将“新的Entry”插入“Hashtable的index位置”,并设置e为“新的Entry”的下一个元素(即“新Entry”为链表表头)。        
    197         tab[index] = new Entry<K,V>(hash, key, value, e);
    198         // (05) 将“Hashtable的实际容量”+1
    199         count++;
    200         return null;
    201     }
    202 
    203     // 删除Hashtable中键为key的元素
    204     public synchronized V remove(Object key) {
    205         Entry tab[] = table;
    206         int hash = key.hashCode();
    207         int index = (hash & 0x7FFFFFFF) % tab.length;
    208         // 找到“key对应的Entry(链表)”
    209         // 然后在链表中找出要删除的节点,并删除该节点。
    210         for (Entry<K,V> e = tab[index], prev = null ; e != null ; prev = e, e = e.next) {
    211             if ((e.hash == hash) && e.key.equals(key)) {
    212                 modCount++;
    213                 if (prev != null) {
    214                     prev.next = e.next;
    215                 } else {
    216                     tab[index] = e.next;
    217                 }
    218                 count--;
    219                 V oldValue = e.value;
    220                 e.value = null;
    221                 return oldValue;
    222             }
    223         }
    224         return null;
    225     }
    226 
    227     // 将“Map(t)”的中全部元素逐一添加到Hashtable中
    228     public synchronized void putAll(Map<? extends K, ? extends V> t) {
    229         for (Map.Entry<? extends K, ? extends V> e : t.entrySet())
    230             put(e.getKey(), e.getValue());
    231     }
    232 
    233     // 清空Hashtable
    234     // 将Hashtable的table数组的值全部设为null
    235     public synchronized void clear() {
    236         Entry tab[] = table;
    237         modCount++;
    238         for (int index = tab.length; --index >= 0; )
    239             tab[index] = null;
    240         count = 0;
    241     }
    242 
    243     // 克隆一个Hashtable,并以Object的形式返回。
    244     public synchronized Object clone() {
    245         try {
    246             Hashtable<K,V> t = (Hashtable<K,V>) super.clone();
    247             t.table = new Entry[table.length];
    248             for (int i = table.length ; i-- > 0 ; ) {
    249                 t.table[i] = (table[i] != null)
    250                 ? (Entry<K,V>) table[i].clone() : null;
    251             }
    252             t.keySet = null;
    253             t.entrySet = null;
    254             t.values = null;
    255             t.modCount = 0;
    256             return t;
    257         } catch (CloneNotSupportedException e) {
    258             // this shouldn't happen, since we are Cloneable
    259             throw new InternalError();
    260         }
    261     }
    262 
    263     public synchronized String toString() {
    264         int max = size() - 1;
    265         if (max == -1)
    266             return "{}";
    267 
    268         StringBuilder sb = new StringBuilder();
    269         Iterator<Map.Entry<K,V>> it = entrySet().iterator();
    270 
    271         sb.append('{');
    272         for (int i = 0; ; i++) {
    273             Map.Entry<K,V> e = it.next();
    274             K key = e.getKey();
    275             V value = e.getValue();
    276             sb.append(key   == this ? "(this Map)" : key.toString());
    277             sb.append('=');
    278             sb.append(value == this ? "(this Map)" : value.toString());
    279 
    280             if (i == max)
    281                 return sb.append('}').toString();
    282             sb.append(", ");
    283         }
    284     }
    285 
    286     // 获取Hashtable的枚举类对象
    287     // 若Hashtable的实际大小为0,则返回“空枚举类”对象;
    288     // 否则,返回正常的Enumerator的对象。(Enumerator实现了迭代器和枚举两个接口)
    289     private <T> Enumeration<T> getEnumeration(int type) {
    290     if (count == 0) {
    291         return (Enumeration<T>)emptyEnumerator;
    292     } else {
    293         return new Enumerator<T>(type, false);
    294     }
    295     }
    296 
    297     // 获取Hashtable的迭代器
    298     // 若Hashtable的实际大小为0,则返回“空迭代器”对象;
    299     // 否则,返回正常的Enumerator的对象。(Enumerator实现了迭代器和枚举两个接口)
    300     private <T> Iterator<T> getIterator(int type) {
    301         if (count == 0) {
    302             return (Iterator<T>) emptyIterator;
    303         } else {
    304             return new Enumerator<T>(type, true);
    305         }
    306     }
    307 
    308     // Hashtable的“key的集合”。它是一个Set,意味着没有重复元素
    309     private transient volatile Set<K> keySet = null;
    310     // Hashtable的“key-value的集合”。它是一个Set,意味着没有重复元素
    311     private transient volatile Set<Map.Entry<K,V>> entrySet = null;
    312     // Hashtable的“key-value的集合”。它是一个Collection,意味着可以有重复元素
    313     private transient volatile Collection<V> values = null;
    314 
    315     // 返回一个被synchronizedSet封装后的KeySet对象
    316     // synchronizedSet封装的目的是对KeySet的所有方法都添加synchronized,实现多线程同步
    317     public Set<K> keySet() {
    318         if (keySet == null)
    319             keySet = Collections.synchronizedSet(new KeySet(), this);
    320         return keySet;
    321     }
    322 
    323     // Hashtable的Key的Set集合。
    324     // KeySet继承于AbstractSet,所以,KeySet中的元素没有重复的。
    325     private class KeySet extends AbstractSet<K> {
    326         public Iterator<K> iterator() {
    327             return getIterator(KEYS);
    328         }
    329         public int size() {
    330             return count;
    331         }
    332         public boolean contains(Object o) {
    333             return containsKey(o);
    334         }
    335         public boolean remove(Object o) {
    336             return Hashtable.this.remove(o) != null;
    337         }
    338         public void clear() {
    339             Hashtable.this.clear();
    340         }
    341     }
    342 
    343     // 返回一个被synchronizedSet封装后的EntrySet对象
    344     // synchronizedSet封装的目的是对EntrySet的所有方法都添加synchronized,实现多线程同步
    345     public Set<Map.Entry<K,V>> entrySet() {
    346         if (entrySet==null)
    347             entrySet = Collections.synchronizedSet(new EntrySet(), this);
    348         return entrySet;
    349     }
    350 
    351     // Hashtable的Entry的Set集合。
    352     // EntrySet继承于AbstractSet,所以,EntrySet中的元素没有重复的。
    353     private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
    354         public Iterator<Map.Entry<K,V>> iterator() {
    355             return getIterator(ENTRIES);
    356         }
    357 
    358         public boolean add(Map.Entry<K,V> o) {
    359             return super.add(o);
    360         }
    361 
    362         // 查找EntrySet中是否包含Object(0)
    363         // 首先,在table中找到o对应的Entry(Entry是一个单向链表)
    364         // 然后,查找Entry链表中是否存在Object
    365         public boolean contains(Object o) {
    366             if (!(o instanceof Map.Entry))
    367                 return false;
    368             Map.Entry entry = (Map.Entry)o;
    369             Object key = entry.getKey();
    370             Entry[] tab = table;
    371             int hash = key.hashCode();
    372             int index = (hash & 0x7FFFFFFF) % tab.length;
    373 
    374             for (Entry e = tab[index]; e != null; e = e.next)
    375                 if (e.hash==hash && e.equals(entry))
    376                     return true;
    377             return false;
    378         }
    379 
    380         // 删除元素Object(0)
    381         // 首先,在table中找到o对应的Entry(Entry是一个单向链表)
    382         // 然后,删除链表中的元素Object
    383         public boolean remove(Object o) {
    384             if (!(o instanceof Map.Entry))
    385                 return false;
    386             Map.Entry<K,V> entry = (Map.Entry<K,V>) o;
    387             K key = entry.getKey();
    388             Entry[] tab = table;
    389             int hash = key.hashCode();
    390             int index = (hash & 0x7FFFFFFF) % tab.length;
    391 
    392             for (Entry<K,V> e = tab[index], prev = null; e != null;
    393                  prev = e, e = e.next) {
    394                 if (e.hash==hash && e.equals(entry)) {
    395                     modCount++;
    396                     if (prev != null)
    397                         prev.next = e.next;
    398                     else
    399                         tab[index] = e.next;
    400 
    401                     count--;
    402                     e.value = null;
    403                     return true;
    404                 }
    405             }
    406             return false;
    407         }
    408 
    409         public int size() {
    410             return count;
    411         }
    412 
    413         public void clear() {
    414             Hashtable.this.clear();
    415         }
    416     }
    417 
    418     // 返回一个被synchronizedCollection封装后的ValueCollection对象
    419     // synchronizedCollection封装的目的是对ValueCollection的所有方法都添加synchronized,实现多线程同步
    420     public Collection<V> values() {
    421     if (values==null)
    422         values = Collections.synchronizedCollection(new ValueCollection(),
    423                                                         this);
    424         return values;
    425     }
    426 
    427     // Hashtable的value的Collection集合。
    428     // ValueCollection继承于AbstractCollection,所以,ValueCollection中的元素可以重复的。
    429     private class ValueCollection extends AbstractCollection<V> {
    430         public Iterator<V> iterator() {
    431         return getIterator(VALUES);
    432         }
    433         public int size() {
    434             return count;
    435         }
    436         public boolean contains(Object o) {
    437             return containsValue(o);
    438         }
    439         public void clear() {
    440             Hashtable.this.clear();
    441         }
    442     }
    443 
    444     // 重新equals()函数
    445     // 若两个Hashtable的所有key-value键值对都相等,则判断它们两个相等
    446     public synchronized boolean equals(Object o) {
    447         if (o == this)
    448             return true;
    449 
    450         if (!(o instanceof Map))
    451             return false;
    452         Map<K,V> t = (Map<K,V>) o;
    453         if (t.size() != size())
    454             return false;
    455 
    456         try {
    457             // 通过迭代器依次取出当前Hashtable的key-value键值对
    458             // 并判断该键值对,存在于Hashtable(o)中。
    459             // 若不存在,则立即返回false;否则,遍历完“当前Hashtable”并返回true。
    460             Iterator<Map.Entry<K,V>> i = entrySet().iterator();
    461             while (i.hasNext()) {
    462                 Map.Entry<K,V> e = i.next();
    463                 K key = e.getKey();
    464                 V value = e.getValue();
    465                 if (value == null) {
    466                     if (!(t.get(key)==null && t.containsKey(key)))
    467                         return false;
    468                 } else {
    469                     if (!value.equals(t.get(key)))
    470                         return false;
    471                 }
    472             }
    473         } catch (ClassCastException unused)   {
    474             return false;
    475         } catch (NullPointerException unused) {
    476             return false;
    477         }
    478 
    479         return true;
    480     }
    481 
    482     // 计算Hashtable的哈希值
    483     // 若 Hashtable的实际大小为0 或者 加载因子<0,则返回0。
    484     // 否则,返回“Hashtable中的每个Entry的key和value的异或值 的总和”。
    485     public synchronized int hashCode() {
    486         int h = 0;
    487         if (count == 0 || loadFactor < 0)
    488             return h;  // Returns zero
    489 
    490         loadFactor = -loadFactor;  // Mark hashCode computation in progress
    491         Entry[] tab = table;
    492         for (int i = 0; i < tab.length; i++)
    493             for (Entry e = tab[i]; e != null; e = e.next)
    494                 h += e.key.hashCode() ^ e.value.hashCode();
    495         loadFactor = -loadFactor;  // Mark hashCode computation complete
    496 
    497         return h;
    498     }
    499 
    500     // java.io.Serializable的写入函数
    501     // 将Hashtable的“总的容量,实际容量,所有的Entry”都写入到输出流中
    502     private synchronized void writeObject(java.io.ObjectOutputStream s)
    503         throws IOException
    504     {
    505         // Write out the length, threshold, loadfactor
    506         s.defaultWriteObject();
    507 
    508         // Write out length, count of elements and then the key/value objects
    509         s.writeInt(table.length);
    510         s.writeInt(count);
    511         for (int index = table.length-1; index >= 0; index--) {
    512             Entry entry = table[index];
    513 
    514             while (entry != null) {
    515             s.writeObject(entry.key);
    516             s.writeObject(entry.value);
    517             entry = entry.next;
    518             }
    519         }
    520     }
    521 
    522     // java.io.Serializable的读取函数:根据写入方式读出
    523     // 将Hashtable的“总的容量,实际容量,所有的Entry”依次读出
    524     private void readObject(java.io.ObjectInputStream s)
    525          throws IOException, ClassNotFoundException
    526     {
    527         // Read in the length, threshold, and loadfactor
    528         s.defaultReadObject();
    529 
    530         // Read the original length of the array and number of elements
    531         int origlength = s.readInt();
    532         int elements = s.readInt();
    533 
    534         // Compute new size with a bit of room 5% to grow but
    535         // no larger than the original size.  Make the length
    536         // odd if it's large enough, this helps distribute the entries.
    537         // Guard against the length ending up zero, that's not valid.
    538         int length = (int)(elements * loadFactor) + (elements / 20) + 3;
    539         if (length > elements && (length & 1) == 0)
    540             length--;
    541         if (origlength > 0 && length > origlength)
    542             length = origlength;
    543 
    544         Entry[] table = new Entry[length];
    545         count = 0;
    546 
    547         // Read the number of elements and then all the key/value objects
    548         for (; elements > 0; elements--) {
    549             K key = (K)s.readObject();
    550             V value = (V)s.readObject();
    551                 // synch could be eliminated for performance
    552                 reconstitutionPut(table, key, value);
    553         }
    554         this.table = table;
    555     }
    556 
    557     private void reconstitutionPut(Entry[] tab, K key, V value)
    558         throws StreamCorruptedException
    559     {
    560         if (value == null) {
    561             throw new java.io.StreamCorruptedException();
    562         }
    563         // Makes sure the key is not already in the hashtable.
    564         // This should not happen in deserialized version.
    565         int hash = key.hashCode();
    566         int index = (hash & 0x7FFFFFFF) % tab.length;
    567         for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
    568             if ((e.hash == hash) && e.key.equals(key)) {
    569                 throw new java.io.StreamCorruptedException();
    570             }
    571         }
    572         // Creates the new entry.
    573         Entry<K,V> e = tab[index];
    574         tab[index] = new Entry<K,V>(hash, key, value, e);
    575         count++;
    576     }
    577 
    578     // Hashtable的Entry节点,它本质上是一个单向链表。
    579     // 也因此,我们才能推断出Hashtable是由拉链法实现的散列表
    580     private static class Entry<K,V> implements Map.Entry<K,V> {
    581         // 哈希值
    582         int hash;
    583         K key;
    584         V value;
    585         // 指向的下一个Entry,即链表的下一个节点
    586         Entry<K,V> next;
    587 
    588         // 构造函数
    589         protected Entry(int hash, K key, V value, Entry<K,V> next) {
    590             this.hash = hash;
    591             this.key = key;
    592             this.value = value;
    593             this.next = next;
    594         }
    595 
    596         protected Object clone() {
    597             return new Entry<K,V>(hash, key, value,
    598                   (next==null ? null : (Entry<K,V>) next.clone()));
    599         }
    600 
    601         public K getKey() {
    602             return key;
    603         }
    604 
    605         public V getValue() {
    606             return value;
    607         }
    608 
    609         // 设置value。若value是null,则抛出异常。
    610         public V setValue(V value) {
    611             if (value == null)
    612                 throw new NullPointerException();
    613 
    614             V oldValue = this.value;
    615             this.value = value;
    616             return oldValue;
    617         }
    618 
    619         // 覆盖equals()方法,判断两个Entry是否相等。
    620         // 若两个Entry的key和value都相等,则认为它们相等。
    621         public boolean equals(Object o) {
    622             if (!(o instanceof Map.Entry))
    623                 return false;
    624             Map.Entry e = (Map.Entry)o;
    625 
    626             return (key==null ? e.getKey()==null : key.equals(e.getKey())) &&
    627                (value==null ? e.getValue()==null : value.equals(e.getValue()));
    628         }
    629 
    630         public int hashCode() {
    631             return hash ^ (value==null ? 0 : value.hashCode());
    632         }
    633 
    634         public String toString() {
    635             return key.toString()+"="+value.toString();
    636         }
    637     }
    638 
    639     private static final int KEYS = 0;
    640     private static final int VALUES = 1;
    641     private static final int ENTRIES = 2;
    642 
    643     // Enumerator的作用是提供了“通过elements()遍历Hashtable的接口” 和 “通过entrySet()遍历Hashtable的接口”。因为,它同时实现了 “Enumerator接口”和“Iterator接口”。
    644     private class Enumerator<T> implements Enumeration<T>, Iterator<T> {
    645         // 指向Hashtable的table
    646         Entry[] table = Hashtable.this.table;
    647         // Hashtable的总的大小
    648         int index = table.length;
    649         Entry<K,V> entry = null;
    650         Entry<K,V> lastReturned = null;
    651         int type;
    652 
    653         // Enumerator是 “迭代器(Iterator)” 还是 “枚举类(Enumeration)”的标志
    654         // iterator为true,表示它是迭代器;否则,是枚举类。
    655         boolean iterator;
    656 
    657         // 在将Enumerator当作迭代器使用时会用到,用来实现fail-fast机制。
    658         protected int expectedModCount = modCount;
    659 
    660         Enumerator(int type, boolean iterator) {
    661             this.type = type;
    662             this.iterator = iterator;
    663         }
    664 
    665         // 从遍历table的数组的末尾向前查找,直到找到不为null的Entry。
    666         public boolean hasMoreElements() {
    667             Entry<K,V> e = entry;
    668             int i = index;
    669             Entry[] t = table;
    670             /* Use locals for faster loop iteration */
    671             while (e == null && i > 0) {
    672                 e = t[--i];
    673             }
    674             entry = e;
    675             index = i;
    676             return e != null;
    677         }
    678 
    679         // 获取下一个元素
    680         // 注意:从hasMoreElements() 和nextElement() 可以看出“Hashtable的elements()遍历方式”
    681         // 首先,从后向前的遍历table数组。table数组的每个节点都是一个单向链表(Entry)。
    682         // 然后,依次向后遍历单向链表Entry。
    683         public T nextElement() {
    684             Entry<K,V> et = entry;
    685             int i = index;
    686             Entry[] t = table;
    687             /* Use locals for faster loop iteration */
    688             while (et == null && i > 0) {
    689                 et = t[--i];
    690             }
    691             entry = et;
    692             index = i;
    693             if (et != null) {
    694                 Entry<K,V> e = lastReturned = entry;
    695                 entry = e.next;
    696                 return type == KEYS ? (T)e.key : (type == VALUES ? (T)e.value : (T)e);
    697             }
    698             throw new NoSuchElementException("Hashtable Enumerator");
    699         }
    700 
    701         // 迭代器Iterator的判断是否存在下一个元素
    702         // 实际上,它是调用的hasMoreElements()
    703         public boolean hasNext() {
    704             return hasMoreElements();
    705         }
    706 
    707         // 迭代器获取下一个元素
    708         // 实际上,它是调用的nextElement()
    709         public T next() {
    710             if (modCount != expectedModCount)
    711                 throw new ConcurrentModificationException();
    712             return nextElement();
    713         }
    714 
    715         // 迭代器的remove()接口。
    716         // 首先,它在table数组中找出要删除元素所在的Entry,
    717         // 然后,删除单向链表Entry中的元素。
    718         public void remove() {
    719             if (!iterator)
    720                 throw new UnsupportedOperationException();
    721             if (lastReturned == null)
    722                 throw new IllegalStateException("Hashtable Enumerator");
    723             if (modCount != expectedModCount)
    724                 throw new ConcurrentModificationException();
    725 
    726             synchronized(Hashtable.this) {
    727                 Entry[] tab = Hashtable.this.table;
    728                 int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length;
    729 
    730                 for (Entry<K,V> e = tab[index], prev = null; e != null;
    731                      prev = e, e = e.next) {
    732                     if (e == lastReturned) {
    733                         modCount++;
    734                         expectedModCount++;
    735                         if (prev == null)
    736                             tab[index] = e.next;
    737                         else
    738                             prev.next = e.next;
    739                         count--;
    740                         lastReturned = null;
    741                         return;
    742                     }
    743                 }
    744                 throw new ConcurrentModificationException();
    745             }
    746         }
    747     }
    748 
    749 
    750     private static Enumeration emptyEnumerator = new EmptyEnumerator();
    751     private static Iterator emptyIterator = new EmptyIterator();
    752 
    753     // 空枚举类
    754     // 当Hashtable的实际大小为0;此时,又要通过Enumeration遍历Hashtable时,返回的是“空枚举类”的对象。
    755     private static class EmptyEnumerator implements Enumeration<Object> {
    756 
    757         EmptyEnumerator() {
    758         }
    759 
    760         // 空枚举类的hasMoreElements() 始终返回false
    761         public boolean hasMoreElements() {
    762             return false;
    763         }
    764 
    765         // 空枚举类的nextElement() 抛出异常
    766         public Object nextElement() {
    767             throw new NoSuchElementException("Hashtable Enumerator");
    768         }
    769     }
    770 
    771 
    772     // 空迭代器
    773     // 当Hashtable的实际大小为0;此时,又要通过迭代器遍历Hashtable时,返回的是“空迭代器”的对象。
    774     private static class EmptyIterator implements Iterator<Object> {
    775 
    776         EmptyIterator() {
    777         }
    778 
    779         public boolean hasNext() {
    780             return false;
    781         }
    782 
    783         public Object next() {
    784             throw new NoSuchElementException("Hashtable Iterator");
    785         }
    786 
    787         public void remove() {
    788             throw new IllegalStateException("Hashtable Iterator");
    789         }
    790 
    791     }
    792 }
    复制代码

    说明在详细介绍Hashtable的代码之前,我们需要了解:和Hashmap一样,Hashtable也是一个散列表,它也是通过“拉链法”解决哈希冲突的。


    第3.1部分 Hashtable的“拉链法”相关内容

    3.1.1 Hashtable数据存储数组

    private transient Entry[] table;

    Hashtable中的key-value都是存储在table数组中的

    3.1.2 数据节点Entry的数据结构

    复制代码
     1 private static class Entry<K,V> implements Map.Entry<K,V> {
     2     // 哈希值
     3     int hash;
     4     K key;
     5     V value;
     6     // 指向的下一个Entry,即链表的下一个节点
     7     Entry<K,V> next;
     8 
     9     // 构造函数
    10     protected Entry(int hash, K key, V value, Entry<K,V> next) {
    11         this.hash = hash;
    12         this.key = key;
    13         this.value = value;
    14         this.next = next;
    15     }
    16 
    17     protected Object clone() {
    18         return new Entry<K,V>(hash, key, value,
    19               (next==null ? null : (Entry<K,V>) next.clone()));
    20     }
    21 
    22     public K getKey() {
    23         return key;
    24     }
    25 
    26     public V getValue() {
    27         return value;
    28     }
    29 
    30     // 设置value。若value是null,则抛出异常。
    31     public V setValue(V value) {
    32         if (value == null)
    33             throw new NullPointerException();
    34 
    35         V oldValue = this.value;
    36         this.value = value;
    37         return oldValue;
    38     }
    39 
    40     // 覆盖equals()方法,判断两个Entry是否相等。
    41     // 若两个Entry的key和value都相等,则认为它们相等。
    42     public boolean equals(Object o) {
    43         if (!(o instanceof Map.Entry))
    44             return false;
    45         Map.Entry e = (Map.Entry)o;
    46 
    47         return (key==null ? e.getKey()==null : key.equals(e.getKey())) &&
    48            (value==null ? e.getValue()==null : value.equals(e.getValue()));
    49     }
    50 
    51     public int hashCode() {
    52         return hash ^ (value==null ? 0 : value.hashCode());
    53     }
    54 
    55     public String toString() {
    56         return key.toString()+"="+value.toString();
    57     }
    58 }
    复制代码

    从中,我们可以看出 Entry 实际上就是一个单向链表。这也是为什么我们说Hashtable是通过拉链法解决哈希冲突的。
    Entry 实现了Map.Entry 接口,即实现getKey(), getValue(), setValue(V value), equals(Object o), hashCode()这些函数。这些都是基本的读取/修改key、value值的函数。

    第3.2部分 Hashtable的构造函数

    Hashtable共包括4个构造函数

    复制代码
     1 // 默认构造函数。
     2 public Hashtable() {
     3     // 默认构造函数,指定的容量大小是11;加载因子是0.75
     4     this(11, 0.75f);
     5 }
     6 
     7 // 指定“容量大小”的构造函数
     8 public Hashtable(int initialCapacity) {
     9     this(initialCapacity, 0.75f);
    10 }
    11 
    12 // 指定“容量大小”和“加载因子”的构造函数
    13 public Hashtable(int initialCapacity, float loadFactor) {
    14     if (initialCapacity < 0)
    15         throw new IllegalArgumentException("Illegal Capacity: "+
    16                                            initialCapacity);
    17     if (loadFactor <= 0 || Float.isNaN(loadFactor))
    18         throw new IllegalArgumentException("Illegal Load: "+loadFactor);
    19 
    20     if (initialCapacity==0)
    21         initialCapacity = 1;
    22     this.loadFactor = loadFactor;
    23     table = new Entry[initialCapacity];
    24     threshold = (int)(initialCapacity * loadFactor);
    25 }
    26 
    27 // 包含“子Map”的构造函数
    28 public Hashtable(Map<? extends K, ? extends V> t) {
    29     this(Math.max(2*t.size(), 11), 0.75f);
    30     // 将“子Map”的全部元素都添加到Hashtable中
    31     putAll(t);
    32 }
    复制代码

    第3.3部分 Hashtable的主要对外接口

    3.3.1 clear()

    clear() 的作用是清空Hashtable。它是将Hashtable的table数组的值全部设为null

    复制代码
    1 public synchronized void clear() {
    2     Entry tab[] = table;
    3     modCount++;
    4     for (int index = tab.length; --index >= 0; )
    5         tab[index] = null;
    6     count = 0;
    7 }
    复制代码

    3.3.2 contains()containsValue()

    contains() 和 containsValue() 的作用都是判断Hashtable是否包含“值(value)”

    复制代码
     1 public boolean containsValue(Object value) {
     2     return contains(value);
     3 }
     4 
     5 public synchronized boolean contains(Object value) {
     6     // Hashtable中“键值对”的value不能是null,
     7     // 若是null的话,抛出异常!
     8     if (value == null) {
     9         throw new NullPointerException();
    10     }
    11 
    12     // 从后向前遍历table数组中的元素(Entry)
    13     // 对于每个Entry(单向链表),逐个遍历,判断节点的值是否等于value
    14     Entry tab[] = table;
    15     for (int i = tab.length ; i-- > 0 ;) {
    16         for (Entry<K,V> e = tab[i] ; e != null ; e = e.next) {
    17             if (e.value.equals(value)) {
    18                 return true;
    19             }
    20         }
    21     }
    22     return false;
    23 }
    复制代码

    3.3.3 containsKey()

    containsKey() 的作用是判断Hashtable是否包含key

    复制代码
     1 public synchronized boolean containsKey(Object key) {
     2     Entry tab[] = table;
     3     int hash = key.hashCode();
     4     // 计算索引值,
     5     // % tab.length 的目的是防止数据越界
     6     int index = (hash & 0x7FFFFFFF) % tab.length;
     7     // 找到“key对应的Entry(链表)”,然后在链表中找出“哈希值”和“键值”与key都相等的元素
     8     for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
     9         if ((e.hash == hash) && e.key.equals(key)) {
    10             return true;
    11         }
    12     }
    13     return false;
    14 }
    复制代码

    3.3.4 elements()

    elements() 的作用是返回“所有value”的枚举对象

    复制代码
     1 public synchronized Enumeration<V> elements() {
     2     return this.<V>getEnumeration(VALUES);
     3 }
     4 
     5 // 获取Hashtable的枚举类对象
     6 private <T> Enumeration<T> getEnumeration(int type) {
     7     if (count == 0) {
     8         return (Enumeration<T>)emptyEnumerator;
     9     } else {
    10         return new Enumerator<T>(type, false);
    11     }
    12 }
    复制代码

    从中,我们可以看出:
    (01) 若Hashtable的实际大小为0,则返回“空枚举类”对象emptyEnumerator;
    (02) 否则,返回正常的Enumerator的对象。(Enumerator实现了迭代器和枚举两个接口)

    我们先看看emptyEnumerator对象是如何实现的

    复制代码
     1 private static Enumeration emptyEnumerator = new EmptyEnumerator();
     2 
     3 // 空枚举类
     4 // 当Hashtable的实际大小为0;此时,又要通过Enumeration遍历Hashtable时,返回的是“空枚举类”的对象。
     5 private static class EmptyEnumerator implements Enumeration<Object> {
     6 
     7     EmptyEnumerator() {
     8     }
     9 
    10     // 空枚举类的hasMoreElements() 始终返回false
    11     public boolean hasMoreElements() {
    12         return false;
    13     }
    14 
    15     // 空枚举类的nextElement() 抛出异常
    16     public Object nextElement() {
    17         throw new NoSuchElementException("Hashtable Enumerator");
    18     }
    19 }
    复制代码

    我们在来看看Enumeration类

    Enumerator的作用是提供了“通过elements()遍历Hashtable的接口” 和 “通过entrySet()遍历Hashtable的接口”。因为,它同时实现了 “Enumerator接口”和“Iterator接口”。

    复制代码
      1 private class Enumerator<T> implements Enumeration<T>, Iterator<T> {
      2     // 指向Hashtable的table
      3     Entry[] table = Hashtable.this.table;
      4     // Hashtable的总的大小
      5     int index = table.length;
      6     Entry<K,V> entry = null;
      7     Entry<K,V> lastReturned = null;
      8     int type;
      9 
     10     // Enumerator是 “迭代器(Iterator)” 还是 “枚举类(Enumeration)”的标志
     11     // iterator为true,表示它是迭代器;否则,是枚举类。
     12     boolean iterator;
     13 
     14     // 在将Enumerator当作迭代器使用时会用到,用来实现fail-fast机制。
     15     protected int expectedModCount = modCount;
     16 
     17     Enumerator(int type, boolean iterator) {
     18         this.type = type;
     19         this.iterator = iterator;
     20     }
     21 
     22     // 从遍历table的数组的末尾向前查找,直到找到不为null的Entry。
     23     public boolean hasMoreElements() {
     24         Entry<K,V> e = entry;
     25         int i = index;
     26         Entry[] t = table;
     27         /* Use locals for faster loop iteration */
     28         while (e == null && i > 0) {
     29             e = t[--i];
     30         }
     31         entry = e;
     32         index = i;
     33         return e != null;
     34     }
     35 
     36     // 获取下一个元素
     37     // 注意:从hasMoreElements() 和nextElement() 可以看出“Hashtable的elements()遍历方式”
     38     // 首先,从后向前的遍历table数组。table数组的每个节点都是一个单向链表(Entry)。
     39     // 然后,依次向后遍历单向链表Entry。
     40     public T nextElement() {
     41         Entry<K,V> et = entry;
     42         int i = index;
     43         Entry[] t = table;
     44         /* Use locals for faster loop iteration */
     45         while (et == null && i > 0) {
     46             et = t[--i];
     47         }
     48         entry = et;
     49         index = i;
     50         if (et != null) {
     51             Entry<K,V> e = lastReturned = entry;
     52             entry = e.next;
     53             return type == KEYS ? (T)e.key : (type == VALUES ? (T)e.value : (T)e);
     54         }
     55         throw new NoSuchElementException("Hashtable Enumerator");
     56     }
     57 
     58     // 迭代器Iterator的判断是否存在下一个元素
     59     // 实际上,它是调用的hasMoreElements()
     60     public boolean hasNext() {
     61         return hasMoreElements();
     62     }
     63 
     64     // 迭代器获取下一个元素
     65     // 实际上,它是调用的nextElement()
     66     public T next() {
     67         if (modCount != expectedModCount)
     68             throw new ConcurrentModificationException();
     69         return nextElement();
     70     }
     71 
     72     // 迭代器的remove()接口。
     73     // 首先,它在table数组中找出要删除元素所在的Entry,
     74     // 然后,删除单向链表Entry中的元素。
     75     public void remove() {
     76         if (!iterator)
     77             throw new UnsupportedOperationException();
     78         if (lastReturned == null)
     79             throw new IllegalStateException("Hashtable Enumerator");
     80         if (modCount != expectedModCount)
     81             throw new ConcurrentModificationException();
     82 
     83         synchronized(Hashtable.this) {
     84             Entry[] tab = Hashtable.this.table;
     85             int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length;
     86 
     87             for (Entry<K,V> e = tab[index], prev = null; e != null;
     88                  prev = e, e = e.next) {
     89                 if (e == lastReturned) {
     90                     modCount++;
     91                     expectedModCount++;
     92                     if (prev == null)
     93                         tab[index] = e.next;
     94                     else
     95                         prev.next = e.next;
     96                     count--;
     97                     lastReturned = null;
     98                     return;
     99                 }
    100             }
    101             throw new ConcurrentModificationException();
    102         }
    103     }
    104 }
    复制代码

    entrySet(), keySet(), keys(), values()的实现方法和elements()差不多,而且源码中已经明确的给出了注释。这里就不再做过多说明了。

    3.3.5 get()

    get() 的作用就是获取key对应的value,没有的话返回null

    复制代码
     1 public synchronized V get(Object key) {
     2     Entry tab[] = table;
     3     int hash = key.hashCode();
     4     // 计算索引值,
     5     int index = (hash & 0x7FFFFFFF) % tab.length;
     6     // 找到“key对应的Entry(链表)”,然后在链表中找出“哈希值”和“键值”与key都相等的元素
     7     for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
     8         if ((e.hash == hash) && e.key.equals(key)) {
     9             return e.value;
    10         }
    11     }
    12     return null;
    13 }
    复制代码

    3.3.6 put()

    put() 的作用是对外提供接口,让Hashtable对象可以通过put()将“key-value”添加到Hashtable中。

    复制代码
     1 public synchronized V put(K key, V value) {
     2     // Hashtable中不能插入value为null的元素!!!
     3     if (value == null) {
     4         throw new NullPointerException();
     5     }
     6 
     7     // 若“Hashtable中已存在键为key的键值对”,
     8     // 则用“新的value”替换“旧的value”
     9     Entry tab[] = table;
    10     int hash = key.hashCode();
    11     int index = (hash & 0x7FFFFFFF) % tab.length;
    12     for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
    13         if ((e.hash == hash) && e.key.equals(key)) {
    14             V old = e.value;
    15             e.value = value;
    16             return old;
    17             }
    18     }
    19 
    20     // 若“Hashtable中不存在键为key的键值对”,
    21     // (01) 将“修改统计数”+1
    22     modCount++;
    23     // (02) 若“Hashtable实际容量” > “阈值”(阈值=总的容量 * 加载因子)
    24     //  则调整Hashtable的大小
    25     if (count >= threshold) {
    26         // Rehash the table if the threshold is exceeded
    27         rehash();
    28 
    29         tab = table;
    30         index = (hash & 0x7FFFFFFF) % tab.length;
    31     }
    32 
    33     // (03) 将“Hashtable中index”位置的Entry(链表)保存到e中
    34     Entry<K,V> e = tab[index];
    35     // (04) 创建“新的Entry节点”,并将“新的Entry”插入“Hashtable的index位置”,并设置e为“新的Entry”的下一个元素(即“新Entry”为链表表头)。        
    36     tab[index] = new Entry<K,V>(hash, key, value, e);
    37     // (05) 将“Hashtable的实际容量”+1
    38     count++;
    39     return null;
    40 }
    复制代码

    3.3.7 putAll()

    putAll() 的作用是将“Map(t)”的中全部元素逐一添加到Hashtable中

    1 public synchronized void putAll(Map<? extends K, ? extends V> t) {
    2     for (Map.Entry<? extends K, ? extends V> e : t.entrySet())
    3         put(e.getKey(), e.getValue());
    4 }

    3.3.8 remove()

    remove() 的作用就是删除Hashtable中键为key的元素

    复制代码
     1 public synchronized V remove(Object key) {
     2     Entry tab[] = table;
     3     int hash = key.hashCode();
     4     int index = (hash & 0x7FFFFFFF) % tab.length;
     5     // 找到“key对应的Entry(链表)”
     6     // 然后在链表中找出要删除的节点,并删除该节点。
     7     for (Entry<K,V> e = tab[index], prev = null ; e != null ; prev = e, e = e.next) {
     8         if ((e.hash == hash) && e.key.equals(key)) {
     9             modCount++;
    10             if (prev != null) {
    11                 prev.next = e.next;
    12             } else {
    13                 tab[index] = e.next;
    14             }
    15             count--;
    16             V oldValue = e.value;
    17             e.value = null;
    18             return oldValue;
    19         }
    20     }
    21     return null;
    22 }
    复制代码

    第3.4部分 Hashtable实现的Cloneable接口

    Hashtable实现了Cloneable接口,即实现了clone()方法。
    clone()方法的作用很简单,就是克隆一个Hashtable对象并返回。

    复制代码
     1 // 克隆一个Hashtable,并以Object的形式返回。
     2 public synchronized Object clone() {
     3     try {
     4         Hashtable<K,V> t = (Hashtable<K,V>) super.clone();
     5         t.table = new Entry[table.length];
     6         for (int i = table.length ; i-- > 0 ; ) {
     7             t.table[i] = (table[i] != null)
     8             ? (Entry<K,V>) table[i].clone() : null;
     9         }
    10         t.keySet = null;
    11         t.entrySet = null;
    12         t.values = null;
    13         t.modCount = 0;
    14         return t;
    15     } catch (CloneNotSupportedException e) {
    16         // this shouldn't happen, since we are Cloneable
    17         throw new InternalError();
    18     }
    19 }
    复制代码

    第3.5部分 Hashtable实现的Serializable接口

    Hashtable实现java.io.Serializable,分别实现了串行读取、写入功能。

    串行写入函数就是将Hashtable的“总的容量,实际容量,所有的Entry”都写入到输出流中
    串行读取函数:根据写入方式读出将Hashtable的“总的容量,实际容量,所有的Entry”依次读出

    复制代码
     1 private synchronized void writeObject(java.io.ObjectOutputStream s)
     2     throws IOException
     3 {
     4     // Write out the length, threshold, loadfactor
     5     s.defaultWriteObject();
     6 
     7     // Write out length, count of elements and then the key/value objects
     8     s.writeInt(table.length);
     9     s.writeInt(count);
    10     for (int index = table.length-1; index >= 0; index--) {
    11         Entry entry = table[index];
    12 
    13         while (entry != null) {
    14         s.writeObject(entry.key);
    15         s.writeObject(entry.value);
    16         entry = entry.next;
    17         }
    18     }
    19 }
    20 
    21 private void readObject(java.io.ObjectInputStream s)
    22      throws IOException, ClassNotFoundException
    23 {
    24     // Read in the length, threshold, and loadfactor
    25     s.defaultReadObject();
    26 
    27     // Read the original length of the array and number of elements
    28     int origlength = s.readInt();
    29     int elements = s.readInt();
    30 
    31     // Compute new size with a bit of room 5% to grow but
    32     // no larger than the original size.  Make the length
    33     // odd if it's large enough, this helps distribute the entries.
    34     // Guard against the length ending up zero, that's not valid.
    35     int length = (int)(elements * loadFactor) + (elements / 20) + 3;
    36     if (length > elements && (length & 1) == 0)
    37         length--;
    38     if (origlength > 0 && length > origlength)
    39         length = origlength;
    40 
    41     Entry[] table = new Entry[length];
    42     count = 0;
    43 
    44     // Read the number of elements and then all the key/value objects
    45     for (; elements > 0; elements--) {
    46         K key = (K)s.readObject();
    47         V value = (V)s.readObject();
    48             // synch could be eliminated for performance
    49             reconstitutionPut(table, key, value);
    50     }
    51     this.table = table;
    52 }
    复制代码

    第4部分 Hashtable遍历方式

    4.1 遍历Hashtable的键值对

    第一步:根据entrySet()获取Hashtable的“键值对”的Set集合。
    第二步:通过Iterator迭代器遍历“第一步”得到的集合。

    复制代码
    // 假设table是Hashtable对象
    // table中的key是String类型,value是Integer类型
    Integer integ = null;
    Iterator iter = table.entrySet().iterator();
    while(iter.hasNext()) {
        Map.Entry entry = (Map.Entry)iter.next();
        // 获取key
        key = (String)entry.getKey();
            // 获取value
        integ = (Integer)entry.getValue();
    }
    复制代码

    4.2 通过Iterator遍历Hashtable的键

    第一步:根据keySet()获取Hashtable的“键”的Set集合。
    第二步:通过Iterator迭代器遍历“第一步”得到的集合。

    复制代码
    // 假设table是Hashtable对象
    // table中的key是String类型,value是Integer类型
    String key = null;
    Integer integ = null;
    Iterator iter = table.keySet().iterator();
    while (iter.hasNext()) {
            // 获取key
        key = (String)iter.next();
            // 根据key,获取value
        integ = (Integer)table.get(key);
    }
    复制代码

    4.3 通过Iterator遍历Hashtable的值

    第一步:根据value()获取Hashtable的“值”的集合。
    第二步:通过Iterator迭代器遍历“第一步”得到的集合。

    复制代码
    // 假设table是Hashtable对象
    // table中的key是String类型,value是Integer类型
    Integer value = null;
    Collection c = table.values();
    Iterator iter= c.iterator();
    while (iter.hasNext()) {
        value = (Integer)iter.next();
    }
    复制代码

    4.4 通过Enumeration遍历Hashtable的键

    第一步:根据keys()获取Hashtable的集合。
    第二步:通过Enumeration遍历“第一步”得到的集合。

    Enumeration enu = table.keys();
    while(enu.hasMoreElements()) {
        System.out.println(enu.nextElement());
    }   

    4.5 通过Enumeration遍历Hashtable的值

    第一步:根据elements()获取Hashtable的集合。
    第二步:通过Enumeration遍历“第一步”得到的集合。

    Enumeration enu = table.elements();
    while(enu.hasMoreElements()) {
        System.out.println(enu.nextElement());
    }

    遍历测试程序如下

    复制代码
      1 import java.util.*;
      2 
      3 /*
      4  * @desc 遍历Hashtable的测试程序。
      5  *   (01) 通过entrySet()去遍历key、value,参考实现函数:
      6  *        iteratorHashtableByEntryset()
      7  *   (02) 通过keySet()去遍历key,参考实现函数:
      8  *        iteratorHashtableByKeyset()
      9  *   (03) 通过values()去遍历value,参考实现函数:
     10  *        iteratorHashtableJustValues()
     11  *   (04) 通过Enumeration去遍历key,参考实现函数:
     12  *        enumHashtableKey()
     13  *   (05) 通过Enumeration去遍历value,参考实现函数:
     14  *        enumHashtableValue()
     15  *
     16  * @author skywang
     17  */
     18 public class HashtableIteratorTest {
     19 
     20     public static void main(String[] args) {
     21         int val = 0;
     22         String key = null;
     23         Integer value = null;
     24         Random r = new Random();
     25         Hashtable table = new Hashtable();
     26 
     27         for (int i=0; i<12; i++) {
     28             // 随机获取一个[0,100)之间的数字
     29             val = r.nextInt(100);
     30             
     31             key = String.valueOf(val);
     32             value = r.nextInt(5);
     33             // 添加到Hashtable中
     34             table.put(key, value);
     35             System.out.println(" key:"+key+" value:"+value);
     36         }
     37         // 通过entrySet()遍历Hashtable的key-value
     38         iteratorHashtableByEntryset(table) ;
     39         
     40         // 通过keySet()遍历Hashtable的key-value
     41         iteratorHashtableByKeyset(table) ;
     42         
     43         // 单单遍历Hashtable的value
     44         iteratorHashtableJustValues(table);        
     45 
     46         // 遍历Hashtable的Enumeration的key
     47         enumHashtableKey(table);
     48 
     49         // 遍历Hashtable的Enumeration的value
     50         //enumHashtableValue(table);
     51     }
     52             
     53     /*
     54      * 通过Enumeration遍历Hashtable的key
     55      * 效率高!
     56      */
     57     private static void enumHashtableKey(Hashtable table) {
     58         if (table == null)
     59             return ;
     60 
     61         System.out.println("
    enumeration Hashtable");
     62         Enumeration enu = table.keys();
     63         while(enu.hasMoreElements()) {
     64             System.out.println(enu.nextElement());
     65         }
     66     }
     67 
     68     
     69     /*
     70      * 通过Enumeration遍历Hashtable的value
     71      * 效率高!
     72      */
     73     private static void enumHashtableValue(Hashtable table) {
     74         if (table == null)
     75             return ;
     76 
     77         System.out.println("
    enumeration Hashtable");
     78         Enumeration enu = table.elements();
     79         while(enu.hasMoreElements()) {
     80             System.out.println(enu.nextElement());
     81         }
     82     }
     83 
     84     /*
     85      * 通过entry set遍历Hashtable
     86      * 效率高!
     87      */
     88     private static void iteratorHashtableByEntryset(Hashtable table) {
     89         if (table == null)
     90             return ;
     91 
     92         System.out.println("
    iterator Hashtable By entryset");
     93         String key = null;
     94         Integer integ = null;
     95         Iterator iter = table.entrySet().iterator();
     96         while(iter.hasNext()) {
     97             Map.Entry entry = (Map.Entry)iter.next();
     98             
     99             key = (String)entry.getKey();
    100             integ = (Integer)entry.getValue();
    101             System.out.println(key+" -- "+integ.intValue());
    102         }
    103     }
    104 
    105     /*
    106      * 通过keyset来遍历Hashtable
    107      * 效率低!
    108      */
    109     private static void iteratorHashtableByKeyset(Hashtable table) {
    110         if (table == null)
    111             return ;
    112 
    113         System.out.println("
    iterator Hashtable By keyset");
    114         String key = null;
    115         Integer integ = null;
    116         Iterator iter = table.keySet().iterator();
    117         while (iter.hasNext()) {
    118             key = (String)iter.next();
    119             integ = (Integer)table.get(key);
    120             System.out.println(key+" -- "+integ.intValue());
    121         }
    122     }
    123     
    124 
    125     /*
    126      * 遍历Hashtable的values
    127      */
    128     private static void iteratorHashtableJustValues(Hashtable table) {
    129         if (table == null)
    130             return ;
    131         
    132         Collection c = table.values();
    133         Iterator iter= c.iterator();
    134         while (iter.hasNext()) {
    135             System.out.println(iter.next());
    136        }
    137     }
    138 }
    复制代码

    第5部分 Hashtable示例

    下面通过一个实例来学习如何使用Hashtable。

    复制代码
     1 import java.util.*;
     2 
     3 /*
     4  * @desc Hashtable的测试程序。
     5  *
     6  * @author skywang
     7  */
     8 public class HashtableTest {
     9     public static void main(String[] args) {
    10         testHashtableAPIs();
    11     }
    12 
    13     private static void testHashtableAPIs() {
    14         // 初始化随机种子
    15         Random r = new Random();
    16         // 新建Hashtable
    17         Hashtable table = new Hashtable();
    18         // 添加操作
    19         table.put("one", r.nextInt(10));
    20         table.put("two", r.nextInt(10));
    21         table.put("three", r.nextInt(10));
    22 
    23         // 打印出table
    24         System.out.println("table:"+table );
    25 
    26         // 通过Iterator遍历key-value
    27         Iterator iter = table.entrySet().iterator();
    28         while(iter.hasNext()) {
    29             Map.Entry entry = (Map.Entry)iter.next();
    30             System.out.println("next : "+ entry.getKey() +" - "+entry.getValue());
    31         }
    32 
    33         // Hashtable的键值对个数        
    34         System.out.println("size:"+table.size());
    35 
    36         // containsKey(Object key) :是否包含键key
    37         System.out.println("contains key two : "+table.containsKey("two"));
    38         System.out.println("contains key five : "+table.containsKey("five"));
    39 
    40         // containsValue(Object value) :是否包含值value
    41         System.out.println("contains value 0 : "+table.containsValue(new Integer(0)));
    42 
    43         // remove(Object key) : 删除键key对应的键值对
    44         table.remove("three");
    45 
    46         System.out.println("table:"+table );
    47 
    48         // clear() : 清空Hashtable
    49         table.clear();
    50 
    51         // isEmpty() : Hashtable是否为空
    52         System.out.println((table.isEmpty()?"table is empty":"table is not empty") );
    53     }
    54 
    55 }
    复制代码

    (某一次)运行结果

    复制代码
    table:{two=5, one=0, three=6}
    next : two - 5
    next : one - 0
    next : three - 6
    size:3
    contains key two : true
    contains key five : false
    contains value 0 : true
    table:{two=5, one=0}
    table is empty
    复制代码
  • 相关阅读:
    json_encode不编码中文字符的方式
    网站备份脚本
    英语动词大全
    多线程和多进程的区别【转载网络】
    解决curl中errno为51和60的错误
    ps修改图片文字
    如何设计充值消费的数据表
    LoRa与NB-IoT对比(转载)
    vuejs 使用vue-cli引入bootstrap
    关于防火墙的规则
  • 原文地址:https://www.cnblogs.com/wzyxidian/p/5204710.html
Copyright © 2011-2022 走看看