`
ahua186186
  • 浏览: 563140 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

Java中HashMap的数据结构和缺陷

 
阅读更多

在Java的世界里,无论类还是各种数据,其结构的处理是整个程序的逻辑以及性能的关键。由于本人接触了一个有关性能与逻辑同时并存的问题,于是就开始研究这方面的问题。找遍了大大小小的论坛,也把《Java 虚拟机规范》,《apress,.java.collections.(2001),.bm.ocr.6.0.shareconnector》,和《Thinking in Java》翻了也找不到很好的答案,于是一气之下把JDK的 src 解压出来研究,扩然开朗,遂写此文,跟大家分享感受和顺便验证我理解还有没有漏洞。 这里就拿HashMap来研究吧。

  HashMap可谓JDK的一大实用工具,把各个Object映射起来,实现了“键--值”对应的快速存取。但实际里面做了些什么呢?

  在这之前,先介绍一下负载因子和容量的属性。大家都知道其实一个 HashMap 的实际容量就 因子*容量,其默认值是 16×0.75=12; 这个很重要,对效率很一定影响!当存入HashMap的对象超过这个容量时,HashMap 就会重新构造存取表。这就是一个大问题,我后面慢慢介绍,反正,如果你已经知道你大概要存放多少个对象,最好设为该实际容量的能接受的数字。

  两个关键的方法,put和get:

  先有这样一个概念,HashMap是声明了 Map,Cloneable, Serializable 接口,和继承了 AbstractMap 类,里面的 Iterator 其实主要都是其内部类HashIterator 和其他几个 iterator 类实现,当然还有一个很重要的继承了Map.Entry 的 Entry 内部类,由于大家都有源代码,大家有兴趣可以看看这部分,我主要想说明的是 Entry 内部类。它包含了hash,value,key 和next 这四个属性,很重要。put的源码如下

  public Object put(Object key, Object value) {
  Object k = maskNull(key);

  这个就是判断键值是否为空,并不很深奥,其实如果为空,它会返回一个static Object 作为键值,这就是为什么HashMap允许空键值的原因。

  int hash = hash(k);
  int i = indexFor(hash, table.length);

  这连续的两步就是 HashMap 最牛的地方!研究完我都汗颜了,其中 hash 就是通过 key 这个Object的 hashcode 进行 hash,然后通过 indexFor 获得在Object table的索引值。

  table???不要惊讶,其实HashMap也神不到哪里去,它就是用 table 来放的。最牛的就是用 hash 能正确的返回索引。其中的hash算法,我跟JDK的作者 Doug 联系过,他建议我看看《The art of programing vol3》可恨的是,我之前就一直在找,我都找不到,他这样一提,我就更加急了,可惜口袋空空啊!!!

  不知道大家有没有留意 put 其实是一个有返回的方法,它会把相同键值的 put 覆盖掉并返回旧的值!如下方法彻底说明了 HashMap 的结构,其实就是一个表加上在相应位置的Entry的链表:

  for (Entry e = table[i]; e != null; e = e.next) {
  if (e.hash == hash && eq(k, e.key)) {
  Object oldvalue = e.value;
  e.value = value; //把新的值赋予给对应键值。
  e.recordAccess(this); //空方法,留待实现
  return oldvalue; //返回相同键值的对应的旧的值。
  }
  }
  modCount++; //结构性更改的次数
  addEntry(hash, k, value, i); //添加新元素,关键所在!
  return null; //没有相同的键值返回
  }

  我们把关键的方法拿出来分析:

  void addEntry(int hash, Object key, Object value, int bucketIndex) {
  table[bucketIndex] = new Entry(hash, key, value, table[bucketIndex]);

  因为 hash 的算法有可能令不同的键值有相同的hash码并有相同的table索引,如:key=“33”和key=Object g的hash都是-8901334,那它经过indexfor之后的索引一定都为i,这样在new的时候这个Entry的next就会指向这个原本的table[i],再有下一个也如此,形成一个链表,和put的循环对定e.next获得旧的值。到这里,HashMap的结构,大家也十分明白了吧?

  if (size++ >= threshold) //这个threshold就是能实际容纳的量
  resize(2 * table.length); //超出这个容量就会将Object table重构

  所谓的重构也不神,就是建一个两倍大的table(我在别的论坛上看到有人说是两倍加1,把我骗了),然后再一个个indexfor进去!注意!!这就是效率!!如果你能让你的HashMap不需要重构那么多次,效率会大大提高!

  说到这里也差不多了,get比put简单得多,大家,了解put,get也差不了多少了。对于collections我是认为,它是适合广泛的,当不完全适合特有的,如果大家的程序需要特殊的用途,自己写吧,其实很简单。(作者是这样跟我说的,他还建议我用LinkedHashMap,我看了源码以后发现,LinkHashMap其实就是继承HashMap的,然后override相应的方法,有兴趣的同人,自己looklook)建个 Object table,写相应的算法,就ok啦。

  举个例子吧,像 Vector,list 啊什么的其实都很简单,最多就多了的同步的声明,其实如果要实现像Vector那种,插入,删除不多的,可以用一个Object table来实现,按索引存取,添加等。

  如果插入,删除比较多的,可以建两个Object table,然后每个元素用含有next结构的,一个table存,如果要插入到i,但是i已经有元素,用next连起来,然后size++,并在另一个table记录其位置。
转自:http://www.it.com.cn/f/edu/053/30/93849.htm
分享到:
评论

相关推荐

    哈希表的原理 数据结构

    在 Java 中,哈希表可以用来实现各种数据结构,如 HashSet、HashMap 等。这些数据结构都使用哈希表来存储和查询数据,从而提高了系统的性能。 哈希表是一种非常有用的数据结构,它的优点是查找速度快、时间算法...

    Java集合框架(JCF:Java Collections Framework)之概述

    它提供了有用的数据结构和算法,减少了程序设计的复杂度。同时,Java 集合框架也鼓励软件的复用,使得程序员可以更方便地使用和重用代码。 在 Java 1.2 之前,Java 没有完整的集合框架,只有一些简单的容器类,如 ...

    java电话薄(文件)

    总的来说,这个Java电话簿程序是一个基础的文件操作和数据管理应用,通过学习和改进它可以加深对Java编程、文件操作和数据结构的理解。对于初学者,这是一个很好的实践项目,而对于经验丰富的开发者,它提供了一个...

    Java基础教程之HashMap迭代删除使用方法

    在Java中,HashMap是一个非常重要的数据结构,它可以快速地存储和检索数据。然而,在实际开发中,我们经常需要删除HashMap中的某些元素,以满足业务需求。迭代删除是其中一种常见的操作方式,它可以帮助我们快速地...

    腾讯校招Java、测试工程师笔试题

    3. 集合框架:熟悉ArrayList、LinkedList、HashMap等数据结构的使用及其底层实现原理。 4. 异常处理:了解如何使用try-catch-finally语句进行异常处理,以及自定义异常。 5. 多线程:理解并发编程的概念,包括线程...

    2024秋招java开发、测试开发最全八股文

    Redis是内存数据库,适用于高速读写场景,支持多种数据结构如字符串、哈希、列表、集合和有序集合。MySQL是关系型数据库,适合持久化存储和复杂查询,支持事务处理、ACID特性。 【测试开发相关】 测试开发涉及编写...

    Java高级特性 第一章 集合框架和泛型

    Collections Framework是Java语言中一个基础的数据结构.framework,它提供了多种类型的数据结构,包括List、Set、Map等,帮助开发者更方便地存储和管理数据。 为什么不推荐使用数组? 数组虽然可以用来存储数据,...

    C++ JAVA 软件测试面试题汇总

    在软件开发领域,C++和Java是两种广泛使用的编程语言,尤其在企业级应用和系统级编程中。软件测试则是确保这些程序质量的关键环节。面试时,面试官常常会针对这些主题提出问题来评估候选人的专业技能和知识深度。...

    Java词频统计算法(使用单词树)

    为了解决上述问题,可以考虑使用单词树(Trie)数据结构来替代`HashMap`。单词树是一种树形数据结构,特别适合用于存储和检索字符串。每个节点代表一个字符,从根节点到任意一个叶子节点的路径表示一个完整的字符串...

    jdk1.7 HashMap中的致命错误:循环链表

    HashMap作为Java中常用的数据结构,其高效性和灵活性深受开发者喜爱。然而,在JDK1.7版本中,HashMap存在一个严重的问题,即“循环链表”(Looping List),这可能导致在多线程环境下性能急剧下降,甚至引发死循环。...

    iLike职场大学生就业指导Java方向

    理解这些数据结构和它们的操作方法对于编写高效代码至关重要。 【异常处理】 在Java中,异常处理是一种错误处理机制,通过try-catch-finally语句块捕获并处理运行时错误。理解如何正确地抛出和处理异常,能够提升...

    java,python,测试面试宝典.zip

    1. **Python基础**:包括语法特性、数据结构(如列表、元组、字典)、控制结构(循环、条件语句)、函数、模块和包。 2. **面向对象编程**:类的创建、继承、多态,以及Python中的特殊方法(如__init__、__str__等...

    Java 笔试面试下载

    对于求职者来说,理解和掌握Java的基本概念、语法特性、数据结构、算法、多线程、网络编程、IO流、异常处理、集合框架等是必要的技能。 描述中的“NULL”意味着没有提供具体的信息,但我们可以通过常规的Java笔试...

    阿里巴巴Java开发手册(嵩山版).pdf

    Apache Beanutils因其简单易用的特点被广泛采用,但根据阿里巴巴Java开发手册的指导原则,其存在若干缺陷: - **性能问题**:相较于其他工具如Spring BeanUtils或Cglib BeanCopier,Apache Beanutils在性能上表现不...

    C++、JAVA+、C、软件测试面试题.rar

    - 集合框架:掌握ArrayList、LinkedList、HashMap等数据结构的特性及用法。 - 异步编程:学习Java的并发工具,如ExecutorService、Future和Callable。 - 泛型:理解泛型的使用,以及类型擦除的概念。 - I/O流:...

    java面试题整理.zip

    6. **其他**:这部分可能包含操作系统知识(如进程与线程、内存管理)、网络协议(TCP/IP、HTTP等)、数据结构与算法、分布式系统、微服务架构等。这些都是软件开发中不可或缺的基础。 7. **综合**:这部分问题可能...

    C、C 、Java及软件测试的笔试、面试题集合Version2

    对于C、C++、Java和软件测试的题目,考生应熟悉数据结构与算法、设计模式、软件工程原则、编程问题解决能力以及测试理论和实践经验。此外,良好的沟通能力和团队协作精神也是雇主看重的素质。 综上所述,C、C++、...

    Java.Bug模式详解.zip

    Java编程语言以其强大的功能和广泛的应用领域而深受程序员喜爱,然而在实际开发过程中,开发者往往会遇到各种bug。"Java.Bug模式详解.zip"这个压缩包文件显然是为了帮助开发者理解和解决这些常见问题。其中包含的...

    职工信息管理系统

    在职工信息管理系统中,可能会用到ArrayList或LinkedList来存储员工对象,或者使用HashMap等数据结构进行快速查找。 4. **数据库连接与操作**:通常使用JDBC(Java Database Connectivity)来与数据库交互,如MySQL...

Global site tag (gtag.js) - Google Analytics