概述
与 HashMap 类似, Hashtable 也是散列表的实现。它的内部结构可以理解为 「数组 + 链表」的形式,结构示意图如下:
Hashtable 的类继承结构与签名如下:
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">public</span> <span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">class</span> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">Hashtable</span><<span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">K</span>,<span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">V</span>></span></span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">extends</span> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">Dictionary</span><<span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">K</span>,<span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">V</span>></span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">implements</span> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">Map</span><<span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">K</span>,<span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">V</span>>, <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">Cloneable</span>, <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">java</span>.<span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">io</span>.<span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">Serializable</span> </span>{}</span>
Hashtable 的 key 和 value 都不能为空(HashMap 的 key 和 value 都允许为空),并且 key 必须要实现 hashCode 方法和 equals 方法。
PS: Hashtable 目前使用不是很多,若无线程安全的需求,推荐使用 HashMap;若需要线程安全的高并发实现,推荐使用 ConcurrentHashMap。
代码分析
Entry 类
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">private</span> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">static</span> <span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">class</span> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">Entry</span><<span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">K</span>,<span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">V</span>> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">implements</span> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">Map</span>.<span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">Entry</span><<span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">K</span>,<span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">V</span>> </span>{</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">final</span> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">int</span> hash;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">final</span> K key;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> V value;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> Entry<K,V> next;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">protected</span> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">Entry(<span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">int</span> hash, K key, V value, Entry<K,V> next)</span> </span>{</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">this</span>.hash = hash;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">this</span>.key = key;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">this</span>.value = value;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">this</span>.next = next;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> }</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">public</span> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">boolean</span> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">equals(Object o)</span> </span>{</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">if</span> (!(o <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">instanceof</span> Map.Entry))</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">return</span> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">false</span>;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> Map.Entry<?,?> e = (Map.Entry<?,?>)o;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">return</span> (key==<span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">null</span> ? e.getKey()==<span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">null</span> : key.equals(e.getKey())) &&</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> (value==<span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">null</span> ? e.getValue()==<span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">null</span> : value.equals(e.getValue()));</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> }</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">public</span> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">int</span> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">hashCode()</span> </span>{</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">return</span> hash ^ Objects.hashCode(value);</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> }</span>
<span style="padding:0px;margin:0px;max-width:1000%;font-style:italic;box-sizing:border-box !important;overflow-wrap:break-word !important;"> // ...</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;">}</span>
Entry 类实现了 Map.Entry 接口,是 Hashtable 中的节点类。
成员变量
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><span style="max-width:1000%;letter-spacing:0.544px;overflow-wrap:break-word !important;"><span style="max-width:1000%;overflow-wrap:break-word !important;"><span style="letter-spacing:0.544px;font-style:italic;">// Hashtable 内部存储元素的数组</span><p style="padding:0px;margin:0px;white-space:pre;display:flex;letter-spacing:0.544px;font-size:14px;box-sizing:border-box !important;overflow-wrap:break-word !important;max-width:1000%;font-family:Consolas, "Liberation Mono", Menlo, Courier, monospace;position:relative;text-align:left;"><span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">private</span> transient Entry<?,?>[] table;</span></p><p style="padding:0px;margin:0px;white-space:pre;display:flex;letter-spacing:0.544px;font-size:14px;box-sizing:border-box !important;overflow-wrap:break-word !important;max-width:1000%;font-family:Consolas, "Liberation Mono", Menlo, Courier, monospace;position:relative;text-align:left;"><span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><br style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;" /></span></p><p style="padding:0px;margin:0px;white-space:pre;display:flex;letter-spacing:0.544px;font-size:14px;box-sizing:border-box !important;overflow-wrap:break-word !important;max-width:1000%;font-family:Consolas, "Liberation Mono", Menlo, Courier, monospace;position:relative;text-align:left;"><span style="padding:0px;margin:0px;max-width:1000%;font-style:italic;box-sizing:border-box !important;overflow-wrap:break-word !important;">// Hashtable 的阈值 (int)(capacity * loadFactor)</span></p><p style="padding:0px;margin:0px;white-space:pre;display:flex;letter-spacing:0.544px;font-size:14px;box-sizing:border-box !important;overflow-wrap:break-word !important;max-width:1000%;font-family:Consolas, "Liberation Mono", Menlo, Courier, monospace;position:relative;text-align:left;"><span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">private</span> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">int</span> threshold;</span></p><p style="padding:0px;margin:0px;white-space:pre;display:flex;letter-spacing:0.544px;font-size:14px;box-sizing:border-box !important;overflow-wrap:break-word !important;max-width:1000%;font-family:Consolas, "Liberation Mono", Menlo, Courier, monospace;position:relative;text-align:left;"><span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><br style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;" /></span></p><p style="padding:0px;margin:0px;white-space:pre;display:flex;letter-spacing:0.544px;font-size:14px;box-sizing:border-box !important;overflow-wrap:break-word !important;max-width:1000%;font-family:Consolas, "Liberation Mono", Menlo, Courier, monospace;position:relative;text-align:left;"><span style="padding:0px;margin:0px;max-width:1000%;font-style:italic;box-sizing:border-box !important;overflow-wrap:break-word !important;">// 负载因子</span></p><p style="padding:0px;margin:0px;white-space:pre;display:flex;letter-spacing:0.544px;font-size:14px;box-sizing:border-box !important;overflow-wrap:break-word !important;max-width:1000%;font-family:Consolas, "Liberation Mono", Menlo, Courier, monospace;position:relative;text-align:left;"><span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">private</span> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">float</span> loadFactor;</span></p><p style="padding:0px;margin:0px;white-space:pre;display:flex;letter-spacing:0.544px;font-size:14px;box-sizing:border-box !important;overflow-wrap:break-word !important;max-width:1000%;font-family:Consolas, "Liberation Mono", Menlo, Courier, monospace;position:relative;text-align:left;"><span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><br style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;" /></span></p><p style="padding:0px;margin:0px;white-space:pre;display:flex;letter-spacing:0.544px;font-size:14px;box-sizing:border-box !important;overflow-wrap:break-word !important;max-width:1000%;font-family:Consolas, "Liberation Mono", Menlo, Courier, monospace;position:relative;text-align:left;"><span style="padding:0px;margin:0px;max-width:1000%;font-style:italic;box-sizing:border-box !important;overflow-wrap:break-word !important;">// 数组能够分配的最大容量</span></p><p style="padding:0px;margin:0px;white-space:pre;display:flex;letter-spacing:0.544px;font-size:14px;box-sizing:border-box !important;overflow-wrap:break-word !important;max-width:1000%;font-family:Consolas, "Liberation Mono", Menlo, Courier, monospace;position:relative;text-align:left;"><span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">private</span> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">static</span> final <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">int</span> MAX_ARRAY_SIZE = Integer.MAX_VALUE - <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">8</span>;</span></p></span></span></span>
构造器
<span style="padding:0px;margin:0px;max-width:1000%;font-style:italic;box-sizing:border-box !important;overflow-wrap:break-word !important;">// 构造一个空的 Hashtable,初始容量为 11,负载因子为 0.75</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">public</span> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">Hashtable</span>()</span> {</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">this</span>(<span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">11</span>, <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">0.75f</span>);</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;">}</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><br style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;" /></span>
<span style="padding:0px;margin:0px;max-width:1000%;font-style:italic;box-sizing:border-box !important;overflow-wrap:break-word !important;">// 构造一个空的 Hashtable,指定初始容量,负载因子为 0.75</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">public</span> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">Hashtable</span>(<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">int</span> initialCapacity</span>)</span> {</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">this</span>(initialCapacity, <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">0.75f</span>);</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;">}</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><br style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;" /></span>
<span style="padding:0px;margin:0px;max-width:1000%;font-style:italic;box-sizing:border-box !important;overflow-wrap:break-word !important;">// 构造一个空的 Hashtable,指定初始容量和负载因子</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">public</span> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">Hashtable</span>(<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">int</span> initialCapacity, <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">float</span> loadFactor</span>)</span> {</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">if</span> (initialCapacity < <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">0</span>)</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">throw</span> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">new</span> IllegalArgumentException(<span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">"Illegal Capacity: "</span>+</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> initialCapacity);</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">if</span> (loadFactor <= <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">0</span> || Float.isNaN(loadFactor))</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">throw</span> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">new</span> IllegalArgumentException(<span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">"Illegal Load: "</span>+loadFactor);</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">if</span> (initialCapacity==<span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">0</span>)</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> initialCapacity = <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">1</span>;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">this</span>.loadFactor = loadFactor;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> table = <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">new</span> Entry<?,?>[initialCapacity];</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> threshold = (<span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">int</span>)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">1</span>);</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;">}</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><br style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;" /></span>
<span style="padding:0px;margin:0px;max-width:1000%;font-style:italic;box-sizing:border-box !important;overflow-wrap:break-word !important;">// 使用给定的 Map 构造一个 Hashtable</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">public</span> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">Hashtable</span>(<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;">Map<? extends K, ? extends V> t</span>)</span> {</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">this</span>(Math.max(<span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">2</span>*t.size(), <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">11</span>), <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">0.75f</span>);</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> putAll(t);</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;">}</span>
主要方法分析
put 方法
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">public</span> synchronized V <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">put</span>(<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;">K key, V <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">value</span></span>)</span> {</span>
<span style="padding:0px;margin:0px;max-width:1000%;font-style:italic;box-sizing:border-box !important;overflow-wrap:break-word !important;"> // Make sure the value is not null (value 不能为空)</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">if</span> (<span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">value</span> == <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">null</span>) {</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">throw</span> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">new</span> NullPointerException();</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> }</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><br style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;" /></span>
<span style="padding:0px;margin:0px;max-width:1000%;font-style:italic;box-sizing:border-box !important;overflow-wrap:break-word !important;"> // Makes sure the key is not already in the hashtable.</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> Entry<?,?> tab[] = table;</span>
<span style="padding:0px;margin:0px;max-width:1000%;font-style:italic;box-sizing:border-box !important;overflow-wrap:break-word !important;"> // 计算 key 在 table 中的索引</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">int</span> hash = key.hashCode();</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">int</span> index = (hash & <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">0x7FFFFFFF</span>) % tab.length;</span>
<span style="padding:0px;margin:0px;max-width:1000%;font-style:italic;box-sizing:border-box !important;overflow-wrap:break-word !important;"> // 判断 key 在 table 中是否已存在,若存在,则用 value 替换旧值</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> @SuppressWarnings(<span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">"unchecked"</span>)</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> Entry<K,V> entry = (Entry<K,V>)tab[index];</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">for</span>(; entry != <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">null</span> ; entry = entry.next) {</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">if</span> ((entry.hash == hash) && entry.key.<span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">equals</span>(key)) {</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> V old = entry.<span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">value</span>;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> entry.<span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">value</span> = <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">value</span>;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">return</span> old;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> }</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> }</span>
<span style="padding:0px;margin:0px;max-width:1000%;font-style:italic;box-sizing:border-box !important;overflow-wrap:break-word !important;"> // 若不存在,则执行 addEntry 方法,将 key-value 添加到 table</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> addEntry(hash, key, <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">value</span>, index);</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">return</span> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">null</span>;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;">}</span>
可以看到,key 或 value 有一个为空都会抛出 NullPointerException 异常,因此二者都不能为空。
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">private</span> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">void</span> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">addEntry</span>(<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">int</span> hash, K key, V <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">value</span>, <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">int</span> index</span>)</span> {</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> modCount++;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> Entry<?,?> tab[] = table;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">if</span> (count >= threshold) {</span>
<span style="padding:0px;margin:0px;max-width:1000%;font-style:italic;box-sizing:border-box !important;overflow-wrap:break-word !important;"> // Rehash the table if the threshold is exceeded</span>
<span style="padding:0px;margin:0px;max-width:1000%;font-style:italic;box-sizing:border-box !important;overflow-wrap:break-word !important;"> // 超过阈值,则扩容</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> rehash();</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> tab = table;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> hash = key.hashCode();</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> index = (hash & <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">0x7FFFFFFF</span>) % tab.length;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> }</span>
<span style="padding:0px;margin:0px;max-width:1000%;font-style:italic;box-sizing:border-box !important;overflow-wrap:break-word !important;"> // Creates the new entry.</span>
<span style="padding:0px;margin:0px;max-width:1000%;font-style:italic;box-sizing:border-box !important;overflow-wrap:break-word !important;"> // 将 key-value 添加到 table 中(头插法,即插到链表的头部)</span>
<span style="padding:0px;margin:0px;max-width:1000%;font-style:italic;box-sizing:border-box !important;overflow-wrap:break-word !important;"> // 即:先拿到 index 位置的元素,若为空,表示插入 entry 后则只有一个元素;</span>
<span style="padding:0px;margin:0px;max-width:1000%;font-style:italic;box-sizing:border-box !important;overflow-wrap:break-word !important;"> // 若不为空,表示该位置已有元素,将已有元素 e 连接到新的 entry 后面</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> @SuppressWarnings(<span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">"unchecked"</span>)</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> Entry<K,V> e = (Entry<K,V>) tab[index];</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> tab[index] = <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">new</span> Entry<>(hash, key, <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">value</span>, e);</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> count++;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;">}</span>
扩容操作 rehash() 如下:
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">protected</span> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">void</span> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">rehash</span>()</span> {</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">int</span> oldCapacity = table.length;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> Entry<?,?>[] oldMap = table;</span>
<span style="padding:0px;margin:0px;max-width:1000%;font-style:italic;box-sizing:border-box !important;overflow-wrap:break-word !important;"> // overflow-conscious code</span>
<span style="padding:0px;margin:0px;max-width:1000%;font-style:italic;box-sizing:border-box !important;overflow-wrap:break-word !important;"> // 新容量为旧容量的 2 倍加 1</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">int</span> newCapacity = (oldCapacity << <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">1</span>) + <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">1</span>;</span>
<span style="padding:0px;margin:0px;max-width:1000%;font-style:italic;box-sizing:border-box !important;overflow-wrap:break-word !important;"> // 若新容量的值超过最大容量 MAX_ARRAY_SIZE,且旧容量为 MAX_ARRAY_SIZE,则直接返回;</span>
<span style="padding:0px;margin:0px;max-width:1000%;font-style:italic;box-sizing:border-box !important;overflow-wrap:break-word !important;"> // 若旧容量值不为 MAX_ARRAY_SIZE,则新容量为 MAX_ARRAY_SIZE.</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">if</span> (newCapacity - MAX_ARRAY_SIZE > <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">0</span>) {</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">if</span> (oldCapacity == MAX_ARRAY_SIZE)</span>
<span style="padding:0px;margin:0px;max-width:1000%;font-style:italic;box-sizing:border-box !important;overflow-wrap:break-word !important;"> // Keep running with MAX_ARRAY_SIZE buckets</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">return</span>;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> newCapacity = MAX_ARRAY_SIZE;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> }</span>
<span style="padding:0px;margin:0px;max-width:1000%;font-style:italic;box-sizing:border-box !important;overflow-wrap:break-word !important;"> // 新建一个 Entry 数组,容量为上面计算的容量大小</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> Entry<?,?>[] newMap = <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">new</span> Entry<?,?>[newCapacity];</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> modCount++;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> threshold = (<span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">int</span>)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">1</span>);</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> table = newMap;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">for</span> (<span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">int</span> i = oldCapacity ; i-- > <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">0</span> ;) {</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">for</span> (Entry<K,V> old = (Entry<K,V>)oldMap[i] ; old != <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">null</span> ; ) {</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> Entry<K,V> e = old;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> old = old.next;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">int</span> index = (e.hash & <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">0x7FFFFFFF</span>) % newCapacity;</span>
<span style="padding:0px;margin:0px;max-width:1000%;font-style:italic;box-sizing:border-box !important;overflow-wrap:break-word !important;"> // 注意这里会调换顺序</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> e.next = (Entry<K,V>)newMap[index];</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> newMap[index] = e;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> }</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> }</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;">}</span>
扩容操作,若 index 位置为链表,且插入顺序为 1、2、3 ,则在该位置的存储顺序为 3、2、1 。扩容时,会从前往后读取元素并操作,因此扩容后的顺序为 3、2、1。示意图:
值得注意的是,put 方法(包括后面分析的 get 和 remove 等方法)带有 synchronized 关键字,Hashtable 就是通过这种方式实现线程安全的。这里锁定的是整个 table,因此并发效率较低,这也是高并发场景下推荐使用 ConcurrentHashMap 的原因。
get 方法
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">public</span> synchronized V <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">get</span>(<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;">Object key</span>)</span> {</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> Entry<?,?> tab[] = table;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">int</span> hash = key.hashCode();</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">int</span> index = (hash & <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">0x7FFFFFFF</span>) % tab.length;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">for</span> (Entry<?,?> e = tab[index] ; e != <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">null</span> ; e = e.next) {</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">if</span> ((e.hash == hash) && e.key.<span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">equals</span>(key)) {</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">return</span> (V)e.<span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">value</span>;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> }</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> }</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">return</span> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">null</span>;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;">}</span>
分析过 put 方法后,get 方法和 remove 方法分析起来就比较简单了,它们和 put 方法类似。
remove 方法
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">public</span> synchronized V <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">remove</span>(<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;">Object key</span>)</span> {</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> Entry<?,?> tab[] = table;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">int</span> hash = key.hashCode();</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">int</span> index = (hash & <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">0x7FFFFFFF</span>) % tab.length;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> @SuppressWarnings(<span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">"unchecked"</span>)</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> Entry<K,V> e = (Entry<K,V>)tab[index];</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">for</span>(Entry<K,V> prev = <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">null</span> ; e != <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">null</span> ; prev = e, e = e.next) {</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">if</span> ((e.hash == hash) && e.key.<span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">equals</span>(key)) {</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> modCount++;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">if</span> (prev != <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">null</span>) {</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> prev.next = e.next;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> } <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">else</span> {</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> tab[index] = e.next;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> }</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> count--;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> V oldValue = e.<span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">value</span>;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> e.<span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">value</span> = <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">null</span>;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">return</span> oldValue;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> }</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> }</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">return</span> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">null</span>;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;">}</span>
三种集合视图 EntrySet、 keySet 和 values 分别如下:
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">private</span> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">transient</span> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">volatile</span> Set<K> keySet;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">private</span> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">transient</span> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">volatile</span> Set<Map.Entry<K,V>> entrySet;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">private</span> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">transient</span> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">volatile</span> Collection<V> values;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><br style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;" /></span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">public</span> Set<K> keySet() {</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">if</span> (keySet == <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">null</span>)</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> keySet = Collections.synchronizedSet(new KeySet(), <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">this</span>);</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">return</span> keySet;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;">}</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><br style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;" /></span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">public</span> Set<Map.Entry<K,V>> entrySet() {</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">if</span> (entrySet==<span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">null</span>)</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> entrySet = Collections.synchronizedSet(new EntrySet(), <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">this</span>);</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">return</span> entrySet;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;">}</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><br style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;" /></span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"><span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">public</span> Collection<V> values() {</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">if</span> (values==<span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">null</span>)</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> values = Collections.synchronizedCollection(new ValueCollection(),</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">this</span>);</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">return</span> values;</span>
<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;">}</span>
小结
1. Hashtable 是散列表的实现,处理散列冲突使用的是链表法,内部结构可以理解为「数组 + 链表」;
2. 默认初始化容量为 11,默认负载因子为 0.75;
3. 线程安全,使用 synchronized 关键字, 并发效率低 ;
4. 若无需保证线程安全,推荐使用 HashMap;若需要线程安全的高并发场景,推荐使用 ConcurrentHashMap。
相关阅读:
JDK源码分析-HashMap(1)
Stay hungry, stay foolish.