[源码解析]HashMap和HashTable的区别(源码分析解读)

来源:互联网 发布:车船税数据和交管局 编辑:程序博客网 时间:2024/06/05 07:00
前言: 
又是一个大好的周末, 可惜今天起来有点晚, 扒开HashMap和HashTable, 看看他们到底有什么区别吧.

先来一段比较拗口的定义:

Hashtable 的实例有两个参数影响其性能:初始容量 和 加载因子。容量 是哈希表中桶 的数量,初始容量 就是哈希表创建时的容量。注意,哈希表的状态为 open:在发生“哈希冲突”的情况下,单个桶会存储多个条目,这些条目必须按顺序搜索。加载因子 是对哈希表在其容量自动增加之前可以达到多满的一个尺度。初始容量和加载因子这两个参数只是对该实现的提示。关于何时以及是否调用 rehash 方法的具体细节则依赖于该实现。

  而HashTable是 基于哈希表的 Map 接口的实现。此实现提供所有可选的映射操作,并允许使用 null 值和 null 键。(除了非同步和允许使用 null 之外,HashMap 类与 Hashtable 大致相同。)此类不保证映射的顺序,特别是它不保证该顺序恒久不变。 此实现假定哈希函数将元素适   当地分布在各桶之间,可为基本操作(get 和 put)提供稳定的性能。迭代 collection 视图所需的时间与 HashMap 实例的“容量”(桶的数量)及其大小(键-值映射关系数)成比例。所以,如果迭代性能很重要,则不要将初始容量设置得太高(或将加载因子设置得太低)。
  

 

一, 实例举证

 1      2     public static void main(String[] args) { 3         Map<String, String> map = new HashMap<String, String>(); 4         map.put("a", "aaa"); 5         map.put("b", "bbb"); 6         map.put("c", "ccc"); 7         map.put("d", "ddd");  8         Iterator<String> iterator = map.keySet().iterator(); 9         while (iterator.hasNext()) {10             Object key = iterator.next();11             System.out.println("map.get(key) is :" + map.get(key));12         }13 14         Hashtable<String, String> tab = new Hashtable<String, String>();15         tab.put("a", "aaa");16         tab.put("b", "bbb");17         tab.put("c", "ccc");18         tab.put("d", "ddd");  19         Iterator<String> iterator_1 = tab.keySet().iterator();20         while (iterator_1.hasNext()) {21             Object key = iterator_1.next();22             System.out.println("tab.get(key) is :" + tab.get(key));23         }24     }25 }

首先上面有这么一段代码, 那么它的输出是什么呢? 

可以看到, HashMap按照正常顺序输出, 而HashTable输出的顺序却有些诡异.

2, 源码分析
看到上面的结果, 那么我们就分别来看下HashMap和HashTable的源码吧.

首先我要来灌输一些思想, 然后再根据这些定义的规则(前人总结出来的) 再去源码中一探究竟.

1)HashTable是同步的,HashMap是非同步的
HashTable中put和get方法:

 1 public synchronized V put(K key, V value) { 2         // Make sure the value is not null 3         if (value == null) { 4             throw new NullPointerException(); 5         } 6  7         // Makes sure the key is not already in the hashtable. 8         Entry<?,?> tab[] = table; 9         int hash = key.hashCode();10         int index = (hash & 0x7FFFFFFF) % tab.length;11         @SuppressWarnings("unchecked")12         Entry<K,V> entry = (Entry<K,V>)tab[index];13         for(; entry != null ; entry = entry.next) {14             if ((entry.hash == hash) && entry.key.equals(key)) {15                 V old = entry.value;16                 entry.value = value;17                 return old;18             }19         }20 21         addEntry(hash, key, value, index);22         return null;23     }

 

 1 public synchronized V get(Object key) { 2         Entry<?,?> tab[] = table; 3         int hash = key.hashCode(); 4         int index = (hash & 0x7FFFFFFF) % tab.length; 5         for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) { 6             if ((e.hash == hash) && e.key.equals(key)) { 7                 return (V)e.value; 8             } 9         }10         return null;11     }

HashMap中put和get方法:

1 public V put(K key, V value) {2       return putVal(hash(key), key, value, false, true);3 }
1 public V get(Object key) {2         Node<K,V> e;3         return (e = getNode(hash(key), key)) == null ? null : e.value;4 }

从以上代码中就能显而易见的看到HashTable中的put和get方法是被synchronized修饰的, 这种做的区别呢? 
由于非线程安全,效率上可能高于Hashtable. 如果当多个线程访问时, 我们可以使用HashTable或者通过Collections.synchronizedMap来同步HashMap。


2)HashTable与HashMap实现的接口一致,但HashTable继承自Dictionary,而HashMap继承自AbstractMap;
HashTable:

 

 HashMap:
 

 

3)HashTable不允许null值(key和value都不可以) ,HashMap允许null值(key和value都可以)。

 在1中我们可以看到HashTable如果value为null就会直接抛出: throw new NullPointerException();
 那么再看看HashMap put value 具体做了什么?

public V put(K key, V value) {        return putVal(hash(key), key, value, false, true);}final V putVal(int hash, K key, V value, boolean onlyIfAbsent,                   boolean evict) {        Node<K,V>[] tab; Node<K,V> p; int n, i;        if ((tab = table) == null || (n = tab.length) == 0)            n = (tab = resize()).length;        if ((p = tab[i = (n - 1) & hash]) == null)            tab[i] = newNode(hash, key, value, null);        else {            Node<K,V> e; K k;            if (p.hash == hash &&                ((k = p.key) == key || (key != null && key.equals(k))))                e = p;            else if (p instanceof TreeNode)                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);            else {                for (int binCount = 0; ; ++binCount) {                    if ((e = p.next) == null) {                        p.next = newNode(hash, key, value, null);                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st                            treeifyBin(tab, hash);                        break;                    }                    if (e.hash == hash &&                        ((k = e.key) == key || (key != null && key.equals(k))))                        break;                    p = e;                }            }            if (e != null) { // existing mapping for key                V oldValue = e.value;                if (!onlyIfAbsent || oldValue == null)                    e.value = value;                afterNodeAccess(e);                return oldValue;            }        }        ++modCount;        if (++size > threshold)            resize();        afterNodeInsertion(evict);        return null;}

由此可见, 并没有value值进行强制的nullCheck.

4)HashTable有一个contains(Object value)功能和containsValue(Object value)功能一样。
这里我们可以直接对比HashMap和HashTable有关Contains的方法:

HashTable中的contains方法在HashMap中就被取消了, 那么我们来具体看下HashTable中的contains方法的作用: 

 1 public synchronized boolean contains(Object value) { 2         if (value == null) { 3             throw new NullPointerException(); 4         } 5  6         Entry<?,?> tab[] = table; 7         for (int i = tab.length ; i-- > 0 ;) { 8             for (Entry<?,?> e = tab[i] ; e != null ; e = e.next) { 9                 if (e.value.equals(value)) {10                     return true;11                 }12             }13         }14         return false;15 }

然后再看下HashTable中的containsValue方法:

1 public boolean containsValue(Object value) {2         return contains(value);3 }

这里就很明显了, contains方法其实做的事情就是containsValue, 里面将value值使用equals进行对比, 所以在HashTable中直接取消了contains方法而是使用containsValue代替.

5)HashTable使用Enumeration进行遍历,HashMap使用Iterator进行遍历。


首先是HashTable中:

 1 private class Enumerator<T> implements Enumeration<T>, Iterator<T> { 2     Entry<?,?>[] table = Hashtable.this.table; 3     int index = table.length; 4     Entry<?,?> entry; 5     Entry<?,?> lastReturned; 6     int type; 7  8     /** 9      * Indicates whether this Enumerator is serving as an Iterator10      * or an Enumeration.  (true -> Iterator).11      */12     boolean iterator;13 14     /**15      * The modCount value that the iterator believes that the backing16      * Hashtable should have.  If this expectation is violated, the iterator17      * has detected concurrent modification.18      */19     protected int expectedModCount = modCount;20 21     Enumerator(int type, boolean iterator) {22         this.type = type;23         this.iterator = iterator;24     }25 26     public boolean hasMoreElements() {27         Entry<?,?> e = entry;28         int i = index;29         Entry<?,?>[] t = table;30         /* Use locals for faster loop iteration */31         while (e == null && i > 0) {32             e = t[--i];33         }34         entry = e;35         index = i;36         return e != null;37     }38 39     @SuppressWarnings("unchecked")40     public T nextElement() {41         Entry<?,?> 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<?,?> 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 methods59     public boolean hasNext() {60         return hasMoreElements();61     }62 63     public T next() {64         if (modCount != expectedModCount)65             throw new ConcurrentModificationException();66         return nextElement();67     }68 69     public void remove() {70         if (!iterator)71             throw new UnsupportedOperationException();72         if (lastReturned == null)73             throw new IllegalStateException("Hashtable Enumerator");74         if (modCount != expectedModCount)75             throw new ConcurrentModificationException();76 77         synchronized(Hashtable.this) {78             Entry<?,?>[] tab = Hashtable.this.table;79             int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length;80 81             @SuppressWarnings("unchecked")82             Entry<K,V> e = (Entry<K,V>)tab[index];83             for(Entry<K,V> prev = null; e != null; prev = e, e = e.next) {84                 if (e == lastReturned) {85                     modCount++;86                     expectedModCount++;87                     if (prev == null)88                         tab[index] = e.next;89                     else90                         prev.next = e.next;91                     count--;92                     lastReturned = null;93                     return;94                 }95             }96             throw new ConcurrentModificationException();97         }98     }99 }
View Code

然后是HashMap中:

 1 abstract class HashIterator { 2         Node<K,V> next;        // next entry to return 3         Node<K,V> current;     // current entry 4         int expectedModCount;  // for fast-fail 5         int index;             // current slot 6  7         HashIterator() { 8             expectedModCount = modCount; 9             Node<K,V>[] t = table;10             current = next = null;11             index = 0;12             if (t != null && size > 0) { // advance to first entry13                 do {} while (index < t.length && (next = t[index++]) == null);14             }15         }16 17         public final boolean hasNext() {18             return next != null;19         }20 21         final Node<K,V> nextNode() {22             Node<K,V>[] t;23             Node<K,V> e = next;24             if (modCount != expectedModCount)25                 throw new ConcurrentModificationException();26             if (e == null)27                 throw new NoSuchElementException();28             if ((next = (current = e).next) == null && (t = table) != null) {29                 do {} while (index < t.length && (next = t[index++]) == null);30             }31             return e;32         }33 34         public final void remove() {35             Node<K,V> p = current;36             if (p == null)37                 throw new IllegalStateException();38             if (modCount != expectedModCount)39                 throw new ConcurrentModificationException();40             current = null;41             K key = p.key;42             removeNode(hash(key), key, null, false, false);43             expectedModCount = modCount;44         }45     }46 47     final class KeyIterator extends HashIterator48         implements Iterator<K> {49         public final K next() { return nextNode().key; }50     }51 52     final class ValueIterator extends HashIterator53         implements Iterator<V> {54         public final V next() { return nextNode().value; }55     }56 57     final class EntryIterator extends HashIterator58         implements Iterator<Map.Entry<K,V>> {59         public final Map.Entry<K,V> next() { return nextNode(); }60     }
View Code

废弃的接口:Enumeration
Enumeration接口是JDK1.0时推出的,是最好的迭代输出接口,最早使用Vector(现在推荐使用ArrayList)时就是使用Enumeration接口进行输出。虽然Enumeration是一个旧的类,但是在JDK1.5之后为Enumeration类进行了扩充,增加了泛型的操作应用。

Enumeration接口常用的方法有hasMoreElements()(判断是否有下一个值)和 nextElement()(取出当前元素),这些方法的功能跟Iterator类似,只是Iterator中存在删除数据的方法,而此接口不存在删除操作。

为什么还要继续使用Enumeration接口
Enumeration和Iterator接口功能相似,而且Iterator的功能还比Enumeration多,那么为什么还要使用Enumeration?这是因为java的发展经历了很长时间,一些比较古老的系统或者类库中的方法还在使用Enumeration接口,因此为了兼容,还是需要使用Enumeration。

下面给出HashTable和HashMap的几种遍历方式:

 1 public class Person { 2     private int age; 3     private String name; 4     private String email; 5     public int getAge() { 6         return age; 7     } 8     public void setAge(int age) { 9         this.age = age;10     }11     public String getName() {12         return name;13     }14     public void setName(String name) {15         this.name = name;16     }17     public String getEmail() {18         return email;19     }20     public void setEmail(String email) {21         this.email = email;22     }23     @Override24     public String toString() {25         return "Person [age=" + age + ", name=" + name + ", email=" + email + "]";26     }27 }
Person.java
  1 public class Test2 {  2     public static void main(String[] args) {  3         Person person1 = new Person();  4         person1.setAge(34);  5         person1.setName("Jacky");  6         person1.setEmail("Jacky@gmail.com");   7   8         Person person2 = new Person();  9         person2.setAge(23); 10         person2.setName("Ajay"); 11         person2.setEmail("Ajay@gmail.com");  12  13         Person person3 = new Person(); 14         person3.setAge(12); 15         person3.setName("Bill"); 16         person3.setEmail("Bill@gmail.com");  17  18         Person person4 = new Person(); 19         person4.setAge(23); 20         person4.setName("Gace"); 21         person4.setEmail("Gace@gmail.com"); 22  23         Person person5 = new Person(); 24         person5.setAge(45); 25         person5.setName("Jim"); 26         person5.setEmail("Jim@gmail.com"); 27  28         Hashtable<String, Person> ht = new Hashtable<String, Person>(); 29         ht.put("1", person1); 30         ht.put("2", person2); 31         ht.put("3", person3); 32         ht.put("4", person4); 33         ht.put("5", person5); 34          35         HashMap<String, Person> hm = new HashMap<String, Person>(); 36         hm.put("1", person1); 37         hm.put("2", person2); 38         hm.put("3", person3); 39         hm.put("4", person4); 40         hm.put("5", person5); 41          42         //HashTable 遍历方式: 43         //第一种遍历方式, 使用key 44         Enumeration<String> keys = ht.keys(); 45         while (keys.hasMoreElements()) { 46             String key = (String) keys.nextElement(); 47             System.out.println("HashTable 的 key 是 : " + key + ", Value 是 : "+ht.get(key)); 48         } 49          50          51         //第二种方式:使用elements() 52         Enumeration<Person> elements = ht.elements(); 53         while (elements.hasMoreElements()) { 54             Person person = (Person) elements.nextElement(); 55             System.out.println(person); 56         } 57          58         //第三种方式:使用keySet() 59         Iterator<String> iterator = ht.keySet().iterator(); 60         while (iterator.hasNext()) { 61             String key = (String) iterator.next(); 62             Person value = hm.get(key); 63              64             System.out.println(key + " " + value); 65         } 66          67         //第四种方式:使用entrySet 68         Iterator<Entry<String, Person>> iterator2 = ht.entrySet().iterator(); 69         while (iterator2.hasNext()) { 70             Map.Entry<String, Person> entry = (Map.Entry<String, Person>) iterator2.next(); 71              72             String key = entry.getKey(); 73             Person value = entry.getValue(); 74              75             System.out.println(key + " " + value); 76         } 77          78         //HashTable 79         //第一种方式 80         Iterator<Entry<String, Person>> iterator3 = hm.entrySet().iterator(); 81         while (iterator3.hasNext()) { 82             Map.Entry<String, Person> entry = (Map.Entry<String, Person>) iterator3.next(); 83              84             String key = entry.getKey(); 85             Person value = entry.getValue(); 86              87             System.out.println(key + " " + value); 88         } 89          90         //第二种方式 91         Iterator<String> iterator4 = hm.keySet().iterator(); 92         // the second method to travel the map 93         while (iterator4.hasNext()) { 94             String key = (String) iterator4.next(); 95             Person value = hm.get(key); 96              97             System.out.println(key + " " + value); 98         } 99     }100 }
Test.java

6)HashTable中hash数组默认大小是11,增加的方式是 old*2+1。HashMap中hash数组的默认大小是16,而且一定是2的指数。

HashMap:

1 /**2      * The default initial capacity - MUST be a power of two.3      */4     static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

HashTable:通常,默认加载因子是 0.75, 这是在时间和空间成本上寻求一种折衷。加载因子过高虽然减少了空间开销,但同时也增加了查找某个条目的时间(在大多数 Hashtable 操作中,包括 get 和 put 操作,都反映了这一点)。

1  // 默认构造函数。2 public Hashtable() {3     // 默认构造函数,指定的容量大小是11;加载因子是0.754     this(11, 0.75f);5 }

 

7)哈希值的使用不同
HashTable:,HashTable直接使用对象的hashCode

1 int hash = key.hashCode();2 int index = (hash & 0x7FFFFFFF) % tab.length;

HashMap:HashMap重新计算hash值,而且用与代替求模:

1 int hash = hash(k);2 int i = indexFor(hash, table.length);3 static int hash(Object x) {4 h ^= (h >>> 20) ^ (h >>> 12);5      return h ^ (h >>> 7) ^ (h >>> 4);6 }7 static int indexFor(int h, int length) {8 return h & (length-1);9 }

 

3,其他关联
3.1HashMap与HashSet的关系

a、HashSet底层是采用HashMap实现的:

1 public HashSet() {2     map = new HashMap<E,Object>();3 }

b、调用HashSet的add方法时,实际上是向HashMap中增加了一行(key-value对),该行的key就是向HashSet增加的那个对象,该行的value就是一个Object类型的常量。

1 private static final Object PRESENT = new Object(); public boolean add(E e) { 2     return map.put(e, PRESENT)==null; 3 } 4 public boolean remove(Object o) { 5     return map.remove(o)==PRESENT; 6 }

3.2 HashMap 和 ConcurrentHashMap 的关系

关于这部分内容建议自己去翻翻源码,ConcurrentHashMap 也是一种线程安全的集合类,他和HashTable也是有区别的,主要区别就是加锁的粒度以及如何加锁,ConcurrentHashMap 的加锁粒度要比HashTable更细一点。将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问。

更多请参考: http://www.hollischuang.com/archives/82


4. HashTable源码奉上

 

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

 

 

 

0 0
原创粉丝点击