`

解读Hashtable

阅读更多

        昨天看到了叶漂兄的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.GIF

        从上面的结构图可以看出,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的结果:

Hashtable1.GIF

    
        以上的讨论基于Java展开的,在C#中的Hashtable实现会有所不同,但是我相信两者的设计应该是差不多的。感谢叶漂和quitgame,给了我思考的机会,也让我感到了基础知识的匮乏,看来是要补补基础知识了。   

        [补充]:在Hashtable的实现代码中,有一个名为rehash的方法用于扩充Hashtable的容量。很明显,当rehash方法被调用以后,每一个键值对相应的index也会改变,也就等于将键值对重新排序了。这也是往不同容量的Hashtable放入相同的键值对会输出不同的键值对序列的原因。在Java中,触发rehash方法的条件很简单:hahtable中的键值对超过某一阀值。默认情况下,该阀值等于hashtable中Entry数组的长度×0.75。

分享到:
评论

相关推荐

    深入解读大厂java面试必考点之HashMap全套学习资料

    HashMap是Java编程语言中最常用的集合类之一,尤其在面试中,HashMap的相关知识是考察...这套学习资料应该包含了HashMap的实例分析、源码解读、常见面试题以及实战演练等内容,确保你全面掌握这一核心Java数据结构。

    j2ee面试题

    ### j2ee面试题知识点详解 #### 1. Hashtable的原理及HashMap与Hashtable的区别 - **Hashtable原理**:`Hashtable`是一种数据结构...以上是对给定文件中的知识点进行了详细解读,希望能帮助到准备j2ee面试的读者们。

    阿里Java面试题集锦

    以下是对这些面试题的详细解读: 一、红黑树的特性: 红黑树是一种自平衡的二叉查找树,其特性包括: 1. 节点颜色要么是红色要么是黑色。 2. 根节点是黑色。 3. 所有叶子节点(NIL节点,空节点)是黑色。 4. 如果一...

    【Java面试+Java学习指南】 一份涵盖大部分Java程序员所需要掌握的核心知识

    解读Java中的回调 反射 泛型 枚举类 Java注解和最佳实践 JavaIO流 多线程 深入理解内部类 javac和javap Java8新特性终极指南 序列化和反序列化 继承、封装、多态的实现原理 容器 Java集合类总结 Java集合详解1:一文...

    scjp collection

    #### 标题解读: 标题“SCJP Collection”暗示了文章的主题是SCJP认证中的集合框架部分。SCJP是Java程序员的一项认证,侧重于测试对Java语言特性的掌握程度。集合框架是Java编程中非常重要的一部分,用于存储和操作...

    阿里巴巴面试指南及其最佳答案解析

    内容概要:本文档涵盖了阿里面试过程中常见的技术问答,详细讲解了包括数据结构(如红黑树)、哈希表对比、并发控制机制(ConcurrentHashMap与HashTable性能对比)、Java类加载机制、数据库事务特性和隔离级别、常用...

    Java工程师面试复习指南

    解读Java中的回调 反射 泛型 枚举类 Java注解和最佳实践 JavaIO流 多线程 深入理解内部类 javac和javap Java8新特性终极指南 序列化和反序列化 继承封装多态的实现原理 集合类 Java集合类总结 Java集合详解:一文读...

    JAVA重要的面试题集

    根据给定文件的信息,我们可以提炼出以下几个重要的JAVA面试知识点: ### 1. 访问修饰符:`public`, `private`, `protected`, 和 默认访问权限(`friendly`)...以上是对给定文件中提到的关键知识点的详细解读和补充。

    PHP数组内存利用率低和弱类型详细解读

    HashTable自身包含了表的大小、元素数量等信息,以及用于遍历的内部指针。每个Bucket(哈希桶)存储一个键值对,即使在空闲状态下也会占用一定的内存。因此,即使是空数组,也会因为这些内部结构而占用一定内存。 ...

    J2EE面试题集锦.pdf

    本文将从给定文件中提炼出的几个关键知识点进行深入分析和解读,帮助读者更好地理解和掌握J2EE的核心概念和技术细节。 ### 一、基础问答 #### 继承性问题 文件中的第一个问题是关于哪些类可以被继承。根据Java...

    J2EE面试题集(附答案)

    #### 一、标题及描述解读 - **标题**:“J2EE面试题集(附答案)”明确指出这是一份面向求职者的面试准备资料,特别强调了J2EE这一领域,并且包含了面试题的答案。 - **描述**:“J2EE面试题集(附答案)是为2011年从职...

    2017年Java面试题,Java开发

    - HashTable, HashMap, ConcurrentHashMap是Map的实现,HashTable是线程安全的,而HashMap不是,ConcurrentHashMap提供了更好的并发性能。 - equals()和hashCode()用于定义对象的内容相等性和哈希码计算,通常在...

    【java系列文章】java 基础知识

    【Java系列文章】Java 基础知识涵盖了Java开发中的核心概念和常见问题,以下是针对这些知识点的详细解析: ...以上就是Java基础知识的详细解读,涵盖了从基础到进阶的多个方面,有助于深入理解Java编程的核心概念。

    CLASS_CONFUSION JS混淆 全

    这个混淆函数的核心在于将原本清晰可读的变量名和表达式替换为难以理解的形式,这样即使有人获取到混淆后的代码,也会因为无法轻易解读而难以复制或利用。 在提供的代码片段中,我们可以看到`CLASS_CONFUSION`构造...

    JAVA面试笔试题汇总-1

    根据提供的文件信息,这里将对其中提及的关键知识点进行详细的解读与扩展。 ### 1. Java 面试笔试题概述 这份文档标题为“JAVA面试笔试题汇总-1”,主要包含了一些Java基础知识的问题,旨在帮助求职者更好地准备...

    JAVA面试常见试题集及答案

    根据提供的文件信息,这里将对其中提及的关键知识点进行详细的解读与扩展。 ### 1. Java 面试常见试题集及答案概览 该文档提到的“JAVA面试常见试题集及答案”是一份包含了122道常见Java面试题及其解答的资料。这...

    java扫描网段

    #### 深入解读 1. **代码结构解析**:该Java类`Ip`实现了`Runnable`接口,意味着它可以被Java线程执行。通过`Ping`静态方法和`run`方法,实现了对指定IP地址的ping操作,并将结果存储在静态`Hashtable`中。 2. **...

    java8源码-JavaRobot:Java学习笔记,JavaLearningNote

    源码解读 String源码系列 List源码系列 ArrayList LinkedList CopyOnWriteArrayList Vector Map源码系列 HashMap LinkedHashMap ConcurrentHashMap TreeMap Hashtable Set源码系列 HashSet LinkedHashSet TreeSet ...

Global site tag (gtag.js) - Google Analytics