转载

JDK源码分析-Hashtable

概述

与 HashMap 类似, Hashtable 也是散列表的实现。它的内部结构可以理解为 「数组 + 链表」的形式,结构示意图如下:

JDK源码分析-Hashtable

Hashtable 的类继承结构与签名如下:

JDK源码分析-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>&lt;<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>&gt;</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>&lt;<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>&gt;</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>&lt;<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>&gt;, <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>&lt;<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>&gt; <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>&lt;<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>&gt; </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&lt;K,V&gt; 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&lt;K,V&gt; 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&lt;?,?&gt; e = (Map.Entry&lt;?,?&gt;)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, &quot;Liberation Mono&quot;, 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&lt;?,?&gt;[] 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, &quot;Liberation Mono&quot;, 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, &quot;Liberation Mono&quot;, 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, &quot;Liberation Mono&quot;, 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, &quot;Liberation Mono&quot;, 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, &quot;Liberation Mono&quot;, 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, &quot;Liberation Mono&quot;, 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, &quot;Liberation Mono&quot;, 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, &quot;Liberation Mono&quot;, 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, &quot;Liberation Mono&quot;, 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 &lt; <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;">&quot;Illegal Capacity: &quot;</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 &lt;= <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;">&quot;Illegal Load: &quot;</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&lt;?,?&gt;[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&lt;? extends K, ? extends V&gt; 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&lt;?,?&gt; 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;">&quot;unchecked&quot;</span>)</span>

<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> Entry&lt;K,V&gt; entry = (Entry&lt;K,V&gt;)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&lt;?,?&gt; 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 &gt;= 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;">&quot;unchecked&quot;</span>)</span>

<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> Entry&lt;K,V&gt; e = (Entry&lt;K,V&gt;) 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&lt;&gt;(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&lt;?,?&gt;[] 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 &lt;&lt; <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 &gt; <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&lt;?,?&gt;[] newMap = <span style="padding:0px;margin:0px;max-width:1000%;box-sizing:border-box !important;overflow-wrap:break-word !important;">new</span> Entry&lt;?,?&gt;[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-- &gt; <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&lt;K,V&gt; old = (Entry&lt;K,V&gt;)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&lt;K,V&gt; 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&lt;K,V&gt;)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。示意图:

JDK源码分析-Hashtable

值得注意的是,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&lt;?,?&gt; 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&lt;?,?&gt; 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&lt;?,?&gt; 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;">&quot;unchecked&quot;</span>)</span>

<span style="margin: 0px; padding: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important;"> Entry&lt;K,V&gt; e = (Entry&lt;K,V&gt;)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&lt;K,V&gt; 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&lt;K&gt; 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&lt;Map.Entry&lt;K,V&gt;&gt; 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&lt;V&gt; 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&lt;K&gt; 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&lt;Map.Entry&lt;K,V&gt;&gt; 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&lt;V&gt; 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.

JDK源码分析-Hashtable

原文  https://juejin.im/post/5d59562cf265da03b31bcc2e
正文到此结束
Loading...