Hashtable是Java中键值对数据结构的实现。您可使用“键”存储和检索“值”,它是存储值的标识符。显然“关键”应该是独一无二的。java
java.util.Hashtable扩展Dictionary并实现Map。具备非空值的对象能够用做键或值。Hashtable的密钥必须实现hashcode()和equals()方法。在这篇文章的最后,你会发现这个条件背后的缘由。数据结构
一般,使用空构造函数 Hashtable()建立Java中的Hashtable。这是一个糟糕的决定,并且常常重复的错误。Hashtable有两个其余构造函数jvm
Hashtable(int initialCapacity)(int initialCapacity )
和函数
Hashtable(int initialCapacity,float loadFactor)(int initialCapacity ,float loadFactor )
。初始容量是在Hashtable实例化时建立的桶数。桶的逻辑空间存储的哈希表。性能
在查看java的Hashtable以前,你应该明白通常的哈希。假设v是要存储的值,k是用于存储/检索的密钥,则h是在表的h(k)处存储v的哈希函数。要获取值计算h(k),以便您能够直接获取v的位置。所以,在键值对表中,您不须要顺序扫描键以识别值。
h(k)是散列函数,它用于找到存储对应值的位置v。h(k)不能计算到不肯定空间。分配给Hashtable的存储在程序中受到限制。所以,散列函数h(k)应该返回该分配频谱(逻辑地址空间)内的一个数字。spa
Java的散列使用从键和值对象使用hashCode()方法进行计算。如下是来自Hashtable的核心代码,其中计算了hashCode'h'。你能够看到key和value的hashCode()方法被调用。code
h += e.key.hashCode() ^ e.value.hashCode();
+= e.key.hashCode() ^ e.value.hashCode();
最好在您的自定义对象中使用hashCode()方法。String具备本身的hashCode方法,它计算hashcode值以下:对象
s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1][0]*31^(n-1) + s[1]*31^(n-2)
+ ... + s[n-1]
若是没有hashCode()方法,那么它是从Object类派生的。如下是来自Object类的hashCode()方法的javadoc注释:blog
返回对象的哈希码值。支持这种方法是为了哈希表的好处,如java.util.Hashtable提供的那些。内存
若是要编写一个自定义的hashCode(),那么请遵循如下合同:
hashCode的通常契约是:不管什么时候在执行Java应用程序时屡次在同一对象上调用该对象,hashCode方法必须始终返回相同的整数,前提是在对象上的equals比较中没有使用任何信息被修改。
如下是提升Hashtable的性能。
若是两个对象根据equals(Object)方法相等,那么在两个对象中的每一个对象上调用hashCode方法必须产生相同的整数结果。
hashCode()经过使用对象的内部地址来保证不一样的整数。
当咱们尝试在分配的地址范围限制范围内限制散列函数的输出时,有可能发生冲突。对于两个不一样的键k1和k2,若是咱们有h(k1)= h(k2),那么这就是哈希表中的碰撞。这是什么意思,咱们的散列函数指示咱们在同一位置存储两个不一样的值(键也不一样)。
当碰撞时,有多种方法能够解决它。命名几个哈希表冲突解决技术,“单独连接”,“开放寻址”,“罗宾盖哈希”,“布谷鸟哈希”等。Java的哈希表使用“分离连接”来在Hashtable中进行冲突解决。
Java使用单独的连接进行冲突解决。回想一下,Hashtable将元素存储在存储桶中。在单独连接中,每一个桶将存储对链表的引用。如今假设你已经存储了一个元素在桶1中。这意味着,在第1桶中,您将有一个链表的引用,在该链表中,您将有两个单元格。在这两个单元格中,您将具备键及其相应的值。
为何要存储密钥?由于当有冲突时,即当两个键产生相同的哈希码并指向相同的存储桶(假设存储桶1)时,您也要将第二个元素存储在同一个存储桶中。将此第二个元素添加到已建立的连接列表做为相邻元素。
如今,当您检索到一个值时,它将计算哈希码并将其引导到具备两个元素的存储桶。您能够顺序扫描这两个元素,并使用它们的equals()方法比较键。当关键数学你获得相应的值。但愿你有理由背后的条件,你的对象必须有hashCode()和equals()方法。
Java在Hashtable中有一个私有静态类Entry。它是一个列表的实现,你能够看到,它存储的关键和价值。
要从您的Java Hashtable得到更好的性能,您须要
使用initialCapacity和loadFactor参数
2)
在实例化Hashtable时明智地使用它们。
initialCapacitiy是在Hashtable实例化时建立的桶数。桶的数量和碰撞的几率是相反的。若是您须要更多的桶数,则碰撞的可能性较小。
例如,若是要存储10个元素,而且若是要将initialCapacity设置为100,那么您将拥有100个桶。您将计算hashCoe()只有10次,频谱为100个桶。碰撞的可能性很是少。
可是,若是要将Hashtable的initialCapacity提供为10,则碰撞的可能性很是大。loadFactor决定什么时候自动增长Hashtable的大小。initialCapacity的默认大小为11,loadFactor为.75若是Hashtable的大小为3/4,则Hashtable的大小将增长。
Java Hashtable中的新容量计算以下:
int newCapacity = oldCapacity * 2 + 1;int newCapacity = oldCapacity * 2 + 1 ;
若是您提供较小的容量和加载因子,而且一般会执行rehash(),这会致使性能问题。所以,为了在Java中实现Hashtable的高效性能,在实例化时,将initialCapacity做为您须要的25%,loadFactor为0.75。