1. package com.wangzhu.map;
  2.  
  3. import java.util.HashMap;
  4.  
  5. /**
  6. * hashCode方法的主要作用是为了配合基于散列的集合一起正常运行,<br/>
  7. * 这样的散列集合包括HashSet、HashMap以及HashTable。<br/>
  8. * 能否可以直接根据hashCode值判断两个对象是否相等呢?<br/>
  9. * 答案:肯定是不可以的,因为不同的对象可能会生成相同的hashCode值。<br/>
  10. * 虽然不能根据hashCode值判断两个对象是否相等,但是可以直接根据hashCode值判断两个对象不等,<br/>
  11. * 如果两个对象的hashCode值不等,则必定是两个不同的对象。如果要判断两个对象是否真正相等,则必须通过equals方法。<br/>
  12. * 也就是说对于两个对象,如果调用equals方法得到的结果为true,则两个对象的hashCode值必定相等。<br/>
  13. * 如果equals方法得到的结果为,则两个对象的hashCode值不一定不同; <br/>
  14. * 如果两个对象的hashCode值不等,则equals方法得到的结果必为;<br/>
  15. * 如果两个对象的hashCode值相等,则equals方法得到的结果未知。<br/>
  16. *
  17. * @author wangzhu
  18. * @date 2015-2-1下午11:22:42
  19. *
  20. */
  21. public class DemoMap2 {
  22.  
  23. /**
  24. * @param args
  25. */
  26. public static void main(String[] args) {
  27. Student stu = new Student(21, "John");
  28. HashMap<Student, Integer> map = new HashMap<Student, Integer>();
  29. map.put(stu, 1);
  30. System.out.println(map.get(stu));//
  31. System.out.println(map.get(new Student(21, "John")));//
  32. /**
  33. * 若Student只重写equals方法而没有没有重写hashCode方法时,则输出为null
  34. */
  35.  
  36. stu.setAge(22);
  37. System.out.println(map.get(stu));// null
  38. /**
  39. * 在程序执行期间,只要equals方法的比较操作用到的信息没有被修改,<br/>
  40. * 那么对这同一个对象调用多次, hashCode方法必须始终如一地返回同一个整数。<br/>
  41. *
  42. * 设计hashCode()时最终稿的因素就是:无论何时,对同一个对象调用hashCode()都应该产生同样的值。<br/>
  43. * 如果在将一个对象用put()添加进HashMap时产生一个hashCode值,而用get()取出时却产生另一个hashCode值,<br/>
  44. * 那么就无法获取该对象了。所以如果你的hashCode方法依赖于对象中易变的数据,用户就要当心了,<br/>
  45. * 因为此数据变化时,hashCode() 方法就会生成一个不同的散列码。<br/>
  46. */
  47. }
  48.  
  49. }
  50.  
  51. class Student {
  52. int age;
  53. String name;
  54.  
  55. public Student(int age, String name) {
  56. super();
  57. this.age = age;
  58. this.name = name;
  59. }
  60.  
  61. public int getAge() {
  62. return age;
  63. }
  64.  
  65. public void setAge(int age) {
  66. this.age = age;
  67. }
  68.  
  69. public String getName() {
  70. return name;
  71. }
  72.  
  73. public void setName(String name) {
  74. this.name = name;
  75. }
  76.  
  77. @Override
  78. public int hashCode() {
  79. final int prime = 31;
  80. int result = 1;
  81. result = (prime * result) + age;
  82. result = (prime * result) + ((name == null) ? 0 : name.hashCode());
  83. return result;
  84. }
  85.  
  86. /**
  87. * 重写时,需要让equals方法与hashCode方法始终在逻辑上保持一致性。
  88. */
  89. @Override
  90. public boolean equals(Object obj) {
  91. if (this == obj) {
  92. return true;
  93. }
  94. if (obj == null) {
  95. return false;
  96. }
  97. if (this.getClass() != obj.getClass()) {
  98. return false;
  99. }
  100. Student other = (Student) obj;
  101. if (age != other.age) {
  102. return false;
  103. }
  104. if (name == null) {
  105. if (other.name != null) {
  106. return false;
  107. }
  108. } else if (!name.equals(other.name)) {
  109. return false;
  110. }
  111. return true;
  112. }
  113.  
  114. }

下面是HashMap中的put方法【JDK1.6】

  1. public V put(K key, V value) {
  2. if (key == null)
  3. return putForNullKey(value);
  4. int hash = hash(key.hashCode());
  5. int i = indexFor(hash, table.length);
  6. for (Entry<K,V> e = table[i]; e != null; e = e.next) {
  7. Object k;
  8. if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
  9. V oldValue = e.value;
  10. e.value = value;
  11. e.recordAccess(this);
  12. return oldValue;
  13. }
  14. }
  15.  
  16. modCount++;
  17. addEntry(hash, key, value, i);
  18. return null;
  19. }

备注:put方法是用来向HashMap中添加新的元素。从put方法的具体实现可知,其会先调用hashCode方法得到该元素的hashCode值【经过处理的】,然后查看其是否存在于table数组中,如果存在则调用equals方法来确定是否是存在该元素;如果存在,则更新value值,否则将新的元素添加到HashMap中。

下面是HashMap中的get方法【JDK1.6】

  1. public V get(Object key) {
  2. if (key == null)
  3. return getForNullKey();
  4. int hash = hash(key.hashCode());
  5. for (Entry<K,V> e = table[indexFor(hash, table.length)];
  6. e != null;
  7. e = e.next) {
  8. Object k;
  9. if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
  10. return e.value;
  11. }
  12. return null;
  13. }

备注:get方法是用来将HashMap中对应Key的值Value取出来。从get方法的具体实现可知,其会先调用hashCode方法得到该元素的hashCode值,然后查看其在table数组中是否存在,如果存在则调用equals方法来确定是Key对应的元素,并返回其Value,否则返回null。

重写equals()方法时,需要同时重写hashCode()方法的更多相关文章

  1. 第九条:覆盖equals方法时总要覆盖hashCode方法

    Object类的hashCode方法: public native int hashCode();   是一个本地方法. 其中这个方法的主要注释如下: Whenever it is invoked o ...

  2. 【Java实战】源码解析为什么覆盖equals方法时总要覆盖hashCode方法

    1.背景知识 本文代码基于jdk1.8分析,<Java编程思想>中有如下描述: 另外再看下Object.java对hashCode()方法的说明: /** * Returns a hash ...

  3. 半夜思考, 为什么建议重写 equals() 方法时, 也要重写 hashCode() 方法

    我说的半夜, 并不是真正的半夜, 指的是在我一个人的时候, 我会去思考一些奇怪的问题. 要理解 hashCode() 需要理解下面三个点: hash契约 哈希冲突 哈希可变 第一点: hash 契约指 ...

  4. 覆写equals方法为什么需要覆写hashCode方法

    覆写equals方法必须覆写hashCode方法,是JDK API上反复说明的,不过为什么要这样做呢?这两个方法之间有什么关系呢? void test() { // Person类的实例作为Map的k ...

  5. 在IE浏览器中执行OpenFlashChart的reload方法时无法刷新的解决方法

    由于项目需求,需要在网页上利用图表展示相关数据的统计信息,采用了OpenFlashChart技术.OpenFlashChart是一款开源的以Flash和Javascript为技术基础的免费图表,用它能 ...

  6. 第八条——覆盖equals方法时需遵守的通用约定

    1)自反性 对于任何非null的引用值x,x.equals(x)必须返回true.---这一点基本上不会有啥问题 2)对称性 对于任何非null的引用值x和y,当且仅当x.equals(y)为true ...

  7. 为什么重写equals时必须重写hashCode方法?

    原文地址:http://www.cnblogs.com/shenliang123/archive/2012/04/16/2452206.html 首先我们先来看下String类的源码:可以发现Stri ...

  8. 为什么重写equals时必须重写hashCode方法?(转发+整理)

    为什么重写equals时必须重写hashCode方法? 原文地址:http://www.cnblogs.com/shenliang123/archive/2012/04/16/2452206.html ...

  9. Effective Java 第三版——11. 重写equals方法时同时也要重写hashcode方法

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

  10. why在重写equals时还必须重写hashcode方法

    首先我们先来看下String类的源码:可以发现String是重写了Object类的equals方法的,并且也重写了hashcode方法 public boolean equals(Object anO ...

随机推荐

  1. zedboard搭建交叉编译环境

    参考:http://blog.csdn.net/xzyiverson/article/details/11264417 我安装的LINUX12.04LTS 双系统 下载好交叉编译软件xilinx-20 ...

  2. 第四届蓝桥杯C/C++A组题目:振兴中华

    首先把题目贴上来吧! 小明参加了学校的趣味运动会,其中的一个项目是:跳格子. 地上画着一些格子,每个格子里写一个字,如下所示:(也可参见图1) 从我做起振 我做起振兴 做起振兴中 起振兴中华 图1 比 ...

  3. $.each遍历json对象

    查看一个简单的jQuery的例子来遍历一个JavaScript数组对象. var json = [ {"id":"1","tagName": ...

  4. 1105. Spiral Matrix (25)

    This time your job is to fill a sequence of N positive integers into a spiral matrix in non-increasi ...

  5. .NET Framework 3.5 安装错误:0x800F0906、0x800F081F、0x800F0907

    使用Add-WindowsFeature 照成的问题 I get the failure below..  If I pick the Server 2012 R2 image from 8/15/2 ...

  6. Virtualbox中安装Openwrt

    Virtualbox:https://www.virtualbox.org/wiki/DownloadsOpenwrt:http://downloads.openwrt.org/backfire/10 ...

  7. 关于Oracle表空间数据文件自增长的一些默认选项

    昨天,一个同事请教了一些关于Oracle表空间数据文件自增长的问题,解答过程中顺便整理起来,以后其他同事有同样的疑问时可以直接查阅. 实验内容: 创建MYTEST表空间,默认不开启自增长. 给MYTE ...

  8. matlab实现贝塞尔曲线绘图pdf查看

    贝塞尔曲线绘图方法: %Program 3.7 Freehand Draw Program Using Bezier Splines %Click in Matlab figure window to ...

  9. Cocos2dx中的四种控件及主要用法

    1.控件:即控制对象,控制按钮之类的精灵 2.主要介绍四大类控件: CCControlSlider:进度条 CCControlSwitch:开关 CCScale9Sprite:9妹图(用于缩放) CC ...

  10. android重写view和viewgroup的区别

    重写view: View类一般用于绘图操作,重写它的onDraw方法,但它不可以包含其他组件,没有addView(View view)方法. 重写viewgroup: ViewGroup是一个组件容器 ...