谈谈HashCode与HashMap##

HashCode

hashCode,即一个Object的散列码。

HashCode的作用:

  1. 对于List、数组等集合而言,HashCode用途不大;
  2. 对于HashMap\HashTable\HashSet等集合而言,HashCode有很重要的价值。

HashCode在上述HashMap等容器中主要是用于寻域,即寻找某个对象在集合中的区域位置,用于提升查询效率。

一个对象势必会存在多个属性字段,而选择什么属性来计算hashCode值,具有一定的考验。因为如果选择的字段太多,而HashCode()在程序执行中调用的非常频繁,势必会影响计算性能;如果选择的太少,计算出来的HashCode势必很容易就会出现重复了。

hashcode与equals

对于Object对象而言,其默认提供的equals方法实现就是简单的return this == obj;即只有两个对象都指向了同一个内存地址对象的时候,才会return true。 对于需要比较内容是否相等的情况时,必须要自行覆写equals方法。

对于覆写equals方法的时候,通常要求必须同时覆写HashCode()方法。hashCode即对象的散列码,int类型。

约定:

  1. 覆写equals方法时必须覆写hashcode()
  2. 如果两个对象的equals方法返回值为true,则两个object对应的HashCode值应该相同
  3. 如果两个对象的equals方法返回false,但是这两个object对应的HashCode是有可能会相同的,(但是必须意识到: HashCode返回独一无二的值,对后续存储此对象的hashtable\hashmap等容器更好的处理有很大帮助。因此覆写的时候可以考虑下hashcode的算法,尽量避免重复情况)

重要的细节

在《Java编程思想》一书中的一段话:

“设计hashCode()时最重要的因素就是:无论何时,对同一个对象调用hashCode()都应该产生同样的值。如果在讲一个对象用put()添加进HashMap时产生一个hashCdoe值,而用get()取出时却产生了另一个hashCode值,那么就无法获取该对象了。所以如果你的hashCode方法依赖于对象中易变的数据,用户就要当心了,因为此数据发生变化时,hashCode()方法就会生成一个不同的散列码”。

这个对编码的实际指导意义就是,在使用类似HashMap等容器的时候,其Key值尽量避免使用可变对象;或者说如果Key值使用了可变变量,务必需要保证此对象作为key值放入map中的时候,与其后续从map中查找的时候,其值不会被改变;换言之,就是如果使用某个对象作为Key值,则此对象的equals和HashCode实现的时候,尽量避免使用易变字段,否则如果对象中属性值变更之后,再去get(key)的时候,就会获取不到。

hashCode实际应用中存在重复的可能性,因此实际编码中为了节省空间而使用HashCode作为HashCode的key值进行存储的做法是不正确的。

HashMap & HashTable###

讲HashMap之前,先说下数组与链表。

  1. 数组:

数组存储区间是连续的,占用内存严重,故空间复杂的很大。但数组的二分查找时间复杂度小,为O(1);数组的特点是:寻址容易,插入和删除困难;

  1. 链表:

链表存储区间离散,占用内存比较宽松,故空间复杂度很小,但时间复杂度很大,达O(N)。链表的特点是:寻址困难,插入和删除容易。

为了综合上述两者的优点,便引申出了本次要重点学习的哈希表。

哈希表的优势:易于寻址、插入删除也容易,且不占太多内存。

hashtable

哈希表是由数组+链表组成的,一个长度为16的数组中,每个元素存储的是一个链表的头结点。那么这些元素是按照什么样的规则存储到数组中呢。一般情况是通过hash(key)%len获得,也就是元素的key的哈希值对数组长度取模得到。比如上述哈希表中,12%16=12,28%16=12,108%16=12,140%16=12。所以12、28、108以及140都存储在数组下标为12的位置。

hashmap

http://blog.csdn.net/hxpjava1/article/details/55670439

hashcode 在 HashMap中的作用

关于HashMap的较为深入的介绍,参见:

http://www.cnblogs.com/chenssy/p/3521565.html

http://blog.csdn.net/hxpjava1/article/details/55670439

HashMap对于hashCode重复场景的容错处理

一般情况下,hashcode重复的可能性还是比较高的(尤其是使用eclipse默认生产HashCode的算法的时候),即使是某些自行定义的hash算法,也无法保证数据量足够大的时候不会出现HashCode重复,那么诸如hashMap之类的容器对象是如何实现HashCode重复的容错处理的呢?

http://www.cnblogs.com/dolphin0520/archive/2012/09/28/2700000.html

解决冲突主要有两种方式。

  1. 开放地址法:

即当一个关键字和另一个关键字发生冲突时,使用某种探测技术在Hash表中形成一个探测序列,然后沿着这个探测序列依次查找下去,当碰到一个空的单元时,则插入其中。比较常用的探测方法有线性探测法,比如有一组关键字{12,13,25,23,38,34,6,84,91},Hash表长为14,Hash函数为address(key)=key%11,当插入12,13,25时可以直接插入,而当插入23时,地址1被占用了,因此沿着地址1依次往下探测(探测步长可以根据情况而定),直到探测到地址4,发现为空,则将23插入其中。

  1. 链地址法:

采用数组和链表相结合的办法,将Hash地址相同的记录存储在一张线性表中,而每张表的表头的序号即为计算得到的Hash地址。如下所示:

HashCode1 --  [E1--> E2 --> E3]
HashCode2 -- [E4--> E5 --> E6 --> E7]
  1. 再哈希法:

当发生冲突时,使用第二个、第三个、哈希函数计算地址,直到无冲突时。缺点:计算时间增加。

JAVA基础4——谈谈HashCode与HashMap相关概念的更多相关文章

  1. JAVA基础(1)之hashCode()

    JAVA基础(1)之hashCode() 看到一篇关于hashCode的文章(),写的很详细明白,瞬间有种恍然大悟的感觉,所以特地转过来.原文:http://blog.csdn.net/fenglib ...

  2. Java基础教程:HashTable与HashMap比较

    Java基础教程:HashTable与HashMap比较 1.  关于HashMap的一些说法: a)  HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体.HashMap的底层结 ...

  3. java基础 (一)之HashMap

    HashMap的存储结构是由数组和链表共同完成.Entry<K,V>[] ,Entry是单向链表. 1 HashMap数据结构 HashMap的底层主要是基于数组和链表来实现的,它之所以有 ...

  4. 【Java基础】谈谈集合.List

    摘自:https://www.cnblogs.com/54chensongxia/p/11722828.html 目录 1. ArrayList 1.1 ArrayList的构造 1.2 add方法 ...

  5. Java基础之集合框架——使用HashMap地图(TryPhoneBook1)

    控制台程序. 首先改进Peron类,使Person可以在地图中用作键,进而存储电话簿中的项.必须添加equals()方法并重写默认的hashCode()方法. import java.io.*; pu ...

  6. Java基础之(四)HashMap(jdk10)

    JDK1.7以前的HashMap jdk1.7中,当冲突时,在冲突的地址上生成一个链表,将冲突的元素的key,通过equals进行比较,相同即覆盖,不同则添加到链表上,此时如果链表过长,效率就会大大降 ...

  7. java基础 (二)之HashMap,HashTable,ConcurrentHashMap区别

    HashTable: put方法加了同步锁synchronized,底层数组+链表实现,无论key还是value都不能为null,线程安全,实现线程安全的方式是在修改数据时锁住整个HashTable, ...

  8. 【Java 基础】谈谈集合.List

    目录 1. ArrayList 1.1 ArrayList的构造 1.2 add方法 1.3 remove方法 1.4 查询方法 1.5 一些其他常用方法 1.6 ArrayList小结 2. Vec ...

  9. 【Java基础】谈谈集合.CopyOnWriteArrayList

    目录 实现原理 遍历时不用加锁的原因 CopyOnWriteArrayLis的缺点 使用场景 总结 参考 本篇博客介绍CopyOnWriteArrayList类,读完本博客你将会了解: 什么是COW机 ...

随机推荐

  1. 【20171025晚】alert(1) to win 第五题 正则表达式过滤

    吃过晚饭,再练一题 第五题 function escape(s) { var text = s.replace(/</g, '<').replace(/"/g, '"' ...

  2. 前端-如何用gulp快速搭建项目(sass预编译,代码压缩,css前缀,浏览器自动刷新,雪碧图合成)

    一:gulp优点: 易于使用 通过代码优于配置的策略,Gulp 让简单的任务简单,复杂的任务可管理: 插件高质 Gulp 严格的插件指南确保插件如你期望的那样简洁高质得工作. 构建快速 利用 Node ...

  3. PHPExcel-1.8导出

    //PHPExcel-1.8导出excel<?phpheader("Content-type: text/html; charset=utf-8");mysql_query( ...

  4. 01-从零玩转JavaWeb-面向过程与面向对象

    配套视频讲解:面向过程面向对象 一.面向过程 所有事情都按顺序一件一件来执行.   二.面向对象 面向对象是将功能通过对象也实现,将功能封装进对象之中 让对象去实现具体的细节   三.面向对象的目的 ...

  5. 【前端GUI】——网站设计的重要知识点总结&思维导图(一)

    前言:网页美术设计具有四大特点,分别为交互性.整合性.多维性以及动态性.完整的网页设计既需要试听元素,也需要版式设计,以求有效的传达信息.在设计的时候,设计者要学会利用框架,也要学会打破框架. 一.优 ...

  6. linux虚拟机局域网网卡配置

    1:配置虚拟机        1-1:打开:虚拟机下编辑->虚拟网络编辑器             选择VMnet信息下的桥接模式,在“桥接到”下拉列表里选择自己的网卡.            ...

  7. C++ 空间配置器(allocator)

    C++ 空间配置器(allocator) 在STL中,Memory Allocator 处于最底层的位置,为一切的 Container 提供存储服务,是一切其他组件的基石.对于一般使用 STL 的用户 ...

  8. Windows环境下多线程编程原理与应用读书笔记(6)————临界段及其应用

    <一>临界段 临界段对象通过提供所有线程必须共享的对象来控制线程.只有拥有临界段对象的线程才能够访问保护的资源.在另一个线程可以访问该资源之前,前一线程必须释放临界段对象,一遍新的线程可以 ...

  9. HDU 6143 Killer Names

    Killer Names Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Tota ...

  10. Sudoku Killer

    Problem Description 自从2006年3月10日至11日的首届数独世界锦标赛以后,数独这项游戏越来越受到人们的喜爱和重视. 据说,在2008北京奥运会上,会将数独列为一个单独的项目进行 ...