解读Hashtable
http://perhaps.cnblogs.com/archive/2006/01/06/312335.html
昨天看到了叶漂兄的Post:《Hashtable的烦恼!》,文中提出有关Hashtable中键值对(key/value pair)排序的问题。其实所谓键值对的排序问题,实质上就是键(key)排序的问题。而一直以来,我都认为Hashtable中的键排序是随机的,因为自己有限的编程经验告诉我:键值对插入的顺序不同会影响键值对的输出顺序,实际上就是影响到键的输出顺序了。在和quitgame讨论了一番之后,我发觉问题远没有自己想象中那么简单。于是对Hashtable进行了一番看似钻牛角尖的研究,终于对Hashtable中键排序有了正确的认识。引发我去思考的C#代码可以参考叶漂的原文,以下给出的是Java的代码(公司里只有WSAD,也只能对Java代码进行分析了):
public class TestHashtable {
public static void main(String[] args){
Hashtable ht = new Hashtable();
ht.put("sichuan","chengdu"); //改变以下四行代码的顺序,可能会改变输出内容的顺序
ht.put("hunan","changsha");
ht.put("beijing","beijing");
ht.put("anhui","hefei");
Enumeration e = ht.keys();
while(e.hasMoreElements()) {
Object key = e.nextElement();
Object value = ht.get(key);
System.out.println(key + " " + value + " " + key.hashCode() + " " + value.hashCode());
}
}
}为了讲述Hashtable键排序的问题,我们先来看Hashtable的结构图:
从上面的结构图可以看出,Hashtable的实质就是一个数组+链表。图中的Entry就是链表的实现,Entry的结构中包含了对自己的另一个实例的引用next,用以指向另外一个Entry。而图中标有数字的部分是一个Entry数组,数字就是这个Entry数组的index。那么往Hashtable增加键值对的时候,index会根据键的hashcode、Entry数组的长度共同决定,从而决定键值对存放在Entry数组的哪个位置。从这种意义来说,当键一定,Entry数组的长度一定的情况下,所得到的index肯定是相同的,也就是说插入顺序应该不会影响输出的顺序才对。然而,还有一个重要的因素没有考虑,就是计算index出现相同值的情况。譬如代码中 "sichuan" 和 "anhui",所得到的index是相同的,在这个时候,Entry的链表功能就发挥作用了:put方法通过Entry的next属性获得对另外一个Entry的引用,然后将后来者放入其中。根据debug得出的结果,"sichuan", "anhui"的index同为2,"hunan"的index为6,"beijing"的index为1,在输出的时候,会以index递减的方式获得键值对。很明显,会改变的输出顺序只有"sichuan"和"anhui"了,也就是说输出只有两种可能:"hunan" - "sichuan" - "anhui" - "beijing"和"hunan" - "anhui" - "sichuan" - "beijing"。以下是运行了示例代码之后,Hashtable的结果:
以上的讨论基于Java展开的,在C#中的Hashtable实现会有所不同,但是我相信两者的设计应该是差不多的。感谢叶漂和quitgame,给了我思考的机会,也让我感到了基础知识的匮乏,看来是要补补基础知识了。
[补充]:在Hashtable的实现代码中,有一个名为rehash的方法用于扩充Hashtable的容量。很明显,当rehash方法被调用以后,每一个键值对相应的index也会改变,也就等于将键值对重新排序了。这也是往不同容量的Hashtable放入相同的键值对会输出不同的键值对序列的原因。在Java中,触发rehash方法的条件很简单:hahtable中的键值对超过某一阀值。默认情况下,该阀值等于hashtable中Entry数组的长度×0.75。
解读Hashtable的更多相关文章
- 源码解读—HashTable
在上一篇学习过HashMap(源码解读—HashMap)之后对hashTable也产生了兴趣,随即便把hashTable的源码看了一下.和hashMap类似,但是也有不同之处. public clas ...
- 【java源码】解读HashTable类背后的实现细节
HashTable这个类实现了哈希表从key映射到value的数据结构形式.任何非null的对象都可以作为key或者value. 要在hashtable中存储和检索对象,作为key的对象必须实现has ...
- ysoserial CommonsColletions7分析
CC7也是一条比较通用的链了,不过对于其原理的话,其实还是挺复杂的.文章如有错误,敬请大佬们斧正 CC7利用的是hashtable#readObject作为反序列化入口.AbstractMap的equ ...
- HashTable、HashMap与ConCurrentHashMap源码解读
HashMap 的数据结构 hashMap 初始的数据结构如下图所示,内部维护一个数组,然后数组上维护一个单链表,有个形象的比喻就是想挂钩一样,数组脚标一样的,一个一个的节点往下挂. 我们可以 ...
- [源码解析]HashMap和HashTable的区别(源码分析解读)
前言: 又是一个大好的周末, 可惜今天起来有点晚, 扒开HashMap和HashTable, 看看他们到底有什么区别吧. 先来一段比较拗口的定义: Hashtable 的实例有两个参数影响其性能:初始 ...
- HashTable的故事----Jdk源码解读
HashTable的故事 很早之前,在讲HashMap的时候,我们就说过hash是散列,把...弄碎的意思.hashtable中的hash也是这个意思,而table呢,是指数据表格,也就是说hasht ...
- HashTable源码解读
一:总述 底层实现原理是用数组+链表,与HashMap一样,但HashTable是线程安全的,HashMap是非线程安全的 下面是其结构图(与hashMap类似) 二:属性说明 /** * The h ...
- HashTable的实现原理
转载:http://wiki.jikexueyuan.com/project/java-collection/hashtable.html 概述 和 HashMap 一样,Hashtable 也是一个 ...
- List、ArrayList、Vector及map、HashTable、HashMap分别的区别
一.List与ArrayList的区别 List->AbstractList->ArrayList (1) List是一个接口,ArrayList是一个实现了List接口 ...
随机推荐
- mybatis12 Usermapper.xml
输入和输出映射 通过parameterType完成输入映射,通过resultType和resultMap完成输出映射. 1.1parameterType传递pojo包装对象 可以定义pojo包装类型扩 ...
- linux 基础学习图解
http://www.cnblogs.com/xiaoluo501395377/category/465892.html
- iOS中Git的使用
打开终端: 查看Git的版本的终端命令:git —version 输入:ssh 查看是否已经存在ssh. 如果存在,先将已有的ssh备份,或者将新建的ssh生成到另外的目录下 如果不存在,通过默认的参 ...
- Caused by: java.lang.ClassNotFoundException: com/sun/tools/internal/xjc/api/XJC
Caused by: java.lang.ClassNotFoundException: com/sun/tools/internal/xjc/api/XJC 缺少com/sun/tools/inte ...
- 11.10 noip模拟试题
1.第K小数 (number.cpp/c/pas) [问题描述] 有两个正整数数列,元素个数分别为N和M.从两个数列中分别任取一个数 相乘,这样一共可以得到N*M个数,询问这N*M个数中第K小数是多少 ...
- hao123 百度品专 按品类 计算 下单数量 商品数量 下单金额?
SELECT * FROM t_tag_source WHERE s_name='hao123'; +--------+----------+---------+--------+-------- ...
- C# - linq查询现有的DataTable
可以通过linq对现有的DataTable进行查询,并将结果拷贝至新的DataTable中例如: // Query the SalesOrderHeader table for orders plac ...
- .Net下的进程间的通讯 -- Windows消息队列
Windows 消息队列(MSMQ),是微软Windows2000以上的操作系统的一个服务,可以提供在计算机间消息的可靠传输,用来在两个进程间进行异步通讯最合适不过了.在.Net中有一个Message ...
- google code 上传源码
在使用google code 的时候 做个备份, git clone https://wushuangzilong@code.google.com/p/maplebanana-proxy/ git c ...
- QVW中实现日期区间的选择功能!
QV在日期的选择上不是很灵活,日期区段的选择可以在列表框中直接用鼠标拖拉区段,如果跨周期比较长了还是不是很方便啦. 下面介绍的方式是完全实现了起始日期的选择功能. 注:日期这个字段在抽取的时候一定要格 ...