博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[源码解析]HashMap和HashTable的区别(源码分析解读)
阅读量:4617 次
发布时间:2019-06-09

本文共 37982 字,大约阅读时间需要 126 分钟。

前言: 

又是一个大好的周末, 可惜今天起来有点晚, 扒开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
map = new HashMap
(); 4 map.put("a", "aaa"); 5 map.put("b", "bbb"); 6 map.put("c", "ccc"); 7 map.put("d", "ddd"); 8 Iterator
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
tab = new Hashtable
();15 tab.put("a", "aaa");16 tab.put("b", "bbb");17 tab.put("c", "ccc");18 tab.put("d", "ddd"); 19 Iterator
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
entry = (Entry
)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
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
[] tab; Node
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
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
)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
implements Enumeration
, Iterator
{ 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
e = (Entry
)tab[index];83 for(Entry
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
next; // next entry to return 3 Node
current; // current entry 4 int expectedModCount; // for fast-fail 5 int index; // current slot 6 7 HashIterator() { 8 expectedModCount = modCount; 9 Node
[] 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
nextNode() {22 Node
[] t;23 Node
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
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
{49 public final K next() { return nextNode().key; }50 }51 52 final class ValueIterator extends HashIterator53 implements Iterator
{54 public final V next() { return nextNode().value; }55 }56 57 final class EntryIterator extends HashIterator58 implements Iterator
> {59 public final Map.Entry
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
ht = new Hashtable
(); 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
hm = new HashMap
(); 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
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
elements = ht.elements(); 53 while (elements.hasMoreElements()) { 54 Person person = (Person) elements.nextElement(); 55 System.out.println(person); 56 } 57 58 //第三种方式:使用keySet() 59 Iterator
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
> iterator2 = ht.entrySet().iterator(); 69 while (iterator2.hasNext()) { 70 Map.Entry
entry = (Map.Entry
) 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
> iterator3 = hm.entrySet().iterator(); 81 while (iterator3.hasNext()) { 82 Map.Entry
entry = (Map.Entry
) 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
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
();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
extends Dictionary
implements Map
, 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
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
keys() { 68 return this.
getEnumeration(KEYS); 69 } 70 71 // 返回“所有value”的枚举对象 72 public synchronized Enumeration
elements() { 73 return this.
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
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
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
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
old = oldMap[i]; old != null;) {149 Entry
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
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
e = tab[index];194 // (04)195 // 创建“新的Entry节点”,并将“新的Entry”插入“Hashtable的index位置”,并设置e为“新的Entry”的下一个元素(即“新Entry”为链表表头)。196 tab[index] = new Entry
(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
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
t) {228 for (Map.Entry
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
t = (Hashtable
) 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
) 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
> it = entrySet().iterator();268 269 sb.append('{');270 for (int i = 0;; i++) {271 Map.Entry
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
Enumeration
getEnumeration(int type) {288 if (count == 0) {289 return (Enumeration
) emptyEnumerator;290 } else {291 return new Enumerator
(type, false);292 }293 }294 295 // 获取Hashtable的迭代器296 // 若Hashtable的实际大小为0,则返回“空迭代器”对象;297 // 否则,返回正常的Enumerator的对象。(Enumerator实现了迭代器和枚举两个接口)298 private
Iterator
getIterator(int type) {299 if (count == 0) {300 return (Iterator
) emptyIterator;301 } else {302 return new Enumerator
(type, true);303 }304 }305 306 // Hashtable的“key的集合”。它是一个Set,意味着没有重复元素307 private transient volatile Set
keySet = null;308 // Hashtable的“key-value的集合”。它是一个Set,意味着没有重复元素309 private transient volatile Set
> entrySet = null;310 // Hashtable的“key-value的集合”。它是一个Collection,意味着可以有重复元素311 private transient volatile Collection
values = null;312 313 // 返回一个被synchronizedSet封装后的KeySet对象314 // synchronizedSet封装的目的是对KeySet的所有方法都添加synchronized,实现多线程同步315 public Set
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
{324 public Iterator
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
> 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
> {356 public Iterator
> iterator() {357 return getIterator(ENTRIES);358 }359 360 public boolean add(Map.Entry
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
entry = (Map.Entry
) 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
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
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
{430 public Iterator
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
t = (Map
) 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
> i = entrySet().iterator();464 while (i.hasNext()) {465 Map.Entry
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
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
e = tab[index];571 tab[index] = new Entry
(hash, key, value, e);572 count++;573 }574 575 // Hashtable的Entry节点,它本质上是一个单向链表。576 // 也因此,我们才能推断出Hashtable是由拉链法实现的散列表577 private static class Entry
implements Map.Entry
{578 // 哈希值579 int hash;580 K key;581 V value;582 // 指向的下一个Entry,即链表的下一个节点583 Entry
next;584 585 // 构造函数586 protected Entry(int hash, K key, V value, Entry
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
(hash, key, value, (next == null ? null : (Entry
) 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
implements Enumeration
, Iterator
{642 // 指向Hashtable的table643 Entry[] table = Hashtable.this.table;644 // Hashtable的总的大小645 int index = table.length;646 Entry
entry = null;647 Entry
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
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
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
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
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
{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 {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

 

 

 

转载于:https://www.cnblogs.com/wang-meng/p/5720805.html

你可能感兴趣的文章
14中程序员性格
查看>>
【HDU4622】Reincarnation
查看>>
花点时间搞清top、clientTop、scrollTop、offsetTop
查看>>
python辅助开发模块(非官方)如pil,mysqldb,openpyxl,xlrd,xlwd
查看>>
Mybatis 查询tinyint(1)的数据库字段时会自动转换成boolean类型
查看>>
easyui tree 模仿ztree 使用扁平化加载json
查看>>
JDBC -- DBUtils
查看>>
linux小知识之grub配置
查看>>
[转]Fedora22添加国内软件源和本地软件源
查看>>
安装svn插件最快速,最简单的方法
查看>>
setTimeOut传参数
查看>>
A bug of "sql*loader"?
查看>>
浏览器的重绘与重排
查看>>
《think in python》学习-6
查看>>
oracle常用字符函数
查看>>
netstat 命令详解
查看>>
nodejs 不支持 typescript (...paramName:any[])剩余参数。变相支持方式。
查看>>
简练网软考知识点整理-风险应对措施(应急计划、弹回计划和权变措施)
查看>>
数据库
查看>>
成语解释
查看>>