转自https://www.cnblogs.com/keyi/p/7119825.html

一、equals方法的作用

1、默认情况(没有覆盖equals方法)下equals方法都是调用Object类的equals方法,而Object的equals方法主要用于判断对象的内存地址引用是不是同一个地址(是不是同一个对象)。

2 、要是类中覆盖了equals方法,那么就要根据具体的代码来确定equals方法的作用了,覆盖后一般都是通过对象的内容是否相等来判断对象是否相等。

没有覆盖equals方法代码如下:

  1. //学生类
  2. public class Student {
  3. private int age;
  4. private String name;
  5. public Student() {
  6. }
  7. public Student(int age, String name) {
  8. super();
  9. this.age = age;
  10. this.name = name;
  11. }
  12. public int getAge() {
  13. return age;
  14. }
  15. public String getName() {
  16. return name;
  17. }
  18. public void setAge(int age) {
  19. this.age = age;
  20. }
  21. public void setName(String name) {
  22. this.name = name;
  23. }
  24. }

测试 代码如下:

  1. import java.util.HashSet;
  2. import java.util.LinkedList;
  3. import java.util.Set;
  4. public class EqualsTest {
  5. public static void main(String[] args) {
  6. LinkedList<Student> list = new LinkedList<Student>();
  7. Set<Student> set = new HashSet<Student>();
  8. Student stu1  = new Student(3,"张三");
  9. Student stu2  = new Student(3,"张三");
  10. System.out.println("stu1 == stu2 : "+(stu1 == stu2));
  11. System.out.println("stu1.equals(stu2) : "+stu1.equals(stu2));
  12. list.add(stu1);
  13. list.add(stu2);
  14. System.out.println("list size:"+ list.size());
  15. set.add(stu1);
  16. set.add(stu2);
  17. System.out.println("set size:"+ set.size());
  18. }
  19. }

运行结果:

stu1 == stu2 : false
stu1.equals(stu2) : false
list size:2
set size:2

结果分析:Student类没有覆盖equals方法,stu1调用equals方法实际上调用的是Object的equals方法。所以采用对象内存地址是否相等来判断对象是否相等。因为是两个新对象所以对象的内存地址不相等,所以stu1.equals(stu2) 是false。

3、我们覆盖一下equals方法(age和name属性),让Student类其通过判断对象的内容是否相等来确定对象是否相等。

覆盖后的Student类:

  1. //学生类
  2. public class Student {
  3. private int age;
  4. private String name;
  5. public Student() {
  6. }
  7. public Student(int age, String name) {
  8. super();
  9. this.age = age;
  10. this.name = name;
  11. }
  12. public int getAge() {
  13. return age;
  14. }
  15. public String getName() {
  16. return name;
  17. }
  18. public void setAge(int age) {
  19. this.age = age;
  20. }
  21. public void setName(String name) {
  22. this.name = name;
  23. }
  24. @Override
  25. public boolean equals(Object obj) {
  26. if (this == obj)
  27. return true;
  28. if (obj == null)
  29. return false;
  30. if (getClass() != obj.getClass())
  31. return false;
  32. Student other = (Student) obj;
  33. if (age != other.age)
  34. return false;
  35. if (name == null) {
  36. if (other.name != null)
  37. return false;
  38. } else if (!name.equals(other.name))
  39. return false;
  40. return true;
  41. }
  42. }

运行结果:

stu1 == stu2 : false
stu1.equals(stu2) : true
list size:2
set size:2

结果分析:因为Student两个对象的age和name属性相等,而且又是通过覆盖equals方法来判断的,所示stu1.equals(stu2) 为true。注意以上几次测试list和set的size都是2

二、HashCode

4、通过以上的代码运行,我们知道equals方法已经生效。接下来我们在覆盖一下hashCode方法(通过age和name属性来生成hashcode)并不覆盖equals方法,其中Hash码是通过age和name生成的。

覆盖hashcode后的Student类:

  1. //学生类
  2. public class Student {
  3. private int age;
  4. private String name;
  5. public Student() {
  6. }
  7. public Student(int age, String name) {
  8. super();
  9. this.age = age;
  10. this.name = name;
  11. }
  12. public int getAge() {
  13. return age;
  14. }
  15. public String getName() {
  16. return name;
  17. }
  18. public void setAge(int age) {
  19. this.age = age;
  20. }
  21. public void setName(String name) {
  22. this.name = name;
  23. }
  24. @Override
  25. public int hashCode() {
  26. final int prime = 31;
  27. int result = 1;
  28. result = prime * result + age;
  29. result = prime * result + ((name == null) ? 0 : name.hashCode());
  30. return result;
  31. }
  32. }

运行结果:

stu1 == stu2 : false
stu1.equals(stu2) : false
list size:2
hashCode :775943
hashCode :775943
set size:2

结果分析:我们并没有覆盖equals方法只覆盖了hashCode方法,两个对象虽然hashCode一样,但在将stu1和stu2放入set集合时由于equals方法比较的两个对象是false,所以就没有在比较两个对象的hashcode值。

5、我们覆盖一下equals方法和hashCode方法。

Student代码如下:

  1. //学生类
  2. public class Student {
  3. private int age;
  4. private String name;
  5. public Student() {
  6. }
  7. public Student(int age, String name) {
  8. super();
  9. this.age = age;
  10. this.name = name;
  11. }
  12. public int getAge() {
  13. return age;
  14. }
  15. public String getName() {
  16. return name;
  17. }
  18. public void setAge(int age) {
  19. this.age = age;
  20. }
  21. public void setName(String name) {
  22. this.name = name;
  23. }
  24. @Override
  25. public int hashCode() {
  26. final int prime = 31;
  27. int result = 1;
  28. result = prime * result + age;
  29. result = prime * result + ((name == null) ? 0 : name.hashCode());
  30. System.out.println("hashCode : "+ result);
  31. return result;
  32. }
  33. @Override
  34. public boolean equals(Object obj) {
  35. if (this == obj)
  36. return true;
  37. if (obj == null)
  38. return false;
  39. if (getClass() != obj.getClass())
  40. return false;
  41. Student other = (Student) obj;
  42. if (age != other.age)
  43. return false;
  44. if (name == null) {
  45. if (other.name != null)
  46. return false;
  47. } else if (!name.equals(other.name))
  48. return false;
  49. return true;
  50. }
  51. }

运行结果:

stu1 == stu2 : false

stu1.equals(stu2) :true

list size:2

hashCode :775943

hashCode :775943

set size:1

结果分析:stu1和stu2通过equals方法比较相等,而且返回的hashCode值一样,所以放入set集合中时只放入了一个对象。

6、下面我们让两个对象equals方法比较相等,但hashCode值不相等试试。

Student类的代码如下:

  1. //学生类
  2. public class Student {
  3. private int age;
  4. private String name;
  5. <span style="color:#ff0000;">private static int index=5;</span>
  6. public Student() {
  7. }
  8. public Student(int age, String name) {
  9. super();
  10. this.age = age;
  11. this.name = name;
  12. }
  13. public int getAge() {
  14. return age;
  15. }
  16. public String getName() {
  17. return name;
  18. }
  19. public void setAge(int age) {
  20. this.age = age;
  21. }
  22. public void setName(String name) {
  23. this.name = name;
  24. }
  25. @Override
  26. public int hashCode() {
  27. final int prime = 31;
  28. int result = 1;
  29. result = prime * result + <span style="color:#ff0000;">(age+index++)</span>;
  30. result = prime * result + ((name == null) ? 0 : name.hashCode());
  31. <span style="color:#ff0000;">System.out.println("result :"+result);</span>
  32. return result;
  33. }
  34. @Override
  35. public boolean equals(Object obj) {
  36. if (this == obj)
  37. return true;
  38. if (obj == null)
  39. return false;
  40. if (getClass() != obj.getClass())
  41. return false;
  42. Student other = (Student) obj;
  43. if (age != other.age)
  44. return false;
  45. if (name == null) {
  46. if (other.name != null)
  47. return false;
  48. } else if (!name.equals(other.name))
  49. return false;
  50. return true;
  51. }
  52. }

运行结果:

stu1 == stu2 : false
stu1.equals(stu2) : true
list size:2
hashCode :776098
hashCode :776129
set size:2

结果分析:虽然stu1和stu2通过equals方法比较相等,但两个对象的hashcode的值并不相等,所以在将stu1和stu2放入set集合中时认为是两个不同的对象。

7、修改stu1的某个属性值

Student代码如下:

  1. //学生类
  2. public class Student {
  3. private int age;
  4. private String name;
  5. public Student() {
  6. }
  7. public Student(int age, String name) {
  8. super();
  9. this.age = age;
  10. this.name = name;
  11. }
  12. public int getAge() {
  13. return age;
  14. }
  15. public String getName() {
  16. return name;
  17. }
  18. public void setAge(int age) {
  19. this.age = age;
  20. }
  21. public void setName(String name) {
  22. this.name = name;
  23. }
  24. @Override
  25. public int hashCode() {
  26. final int prime = 31;
  27. int result = 1;
  28. result = prime * result + age;
  29. result = prime * result + ((name == null) ? 0 : name.hashCode());
  30. System.out.println("hashCode : "+ result);
  31. return result;
  32. }
  33. @Override
  34. public boolean equals(Object obj) {
  35. if (this == obj)
  36. return true;
  37. if (obj == null)
  38. return false;
  39. if (getClass() != obj.getClass())
  40. return false;
  41. Student other = (Student) obj;
  42. if (age != other.age)
  43. return false;
  44. if (name == null) {
  45. if (other.name != null)
  46. return false;
  47. } else if (!name.equals(other.name))
  48. return false;
  49. return true;
  50. }
  51. }

测试代码如下:

  1. import java.util.HashSet;
  2. import java.util.LinkedList;
  3. import java.util.Set;
  4. public class EqualsTest {
  5. public static void main(String[] args) {
  6. LinkedList<Student> list = new LinkedList<Student>();
  7. Set<Student> set = new HashSet<Student>();
  8. Student stu1  = new Student(3,"张三");
  9. Student stu2  = new Student(3,"张三");
  10. System.out.println("stu1 == stu2 : "+(stu1 == stu2));
  11. System.out.println("stu1.equals(stu2) : "+stu1.equals(stu2));
  12. list.add(stu1);
  13. list.add(stu2);
  14. System.out.println("list size:"+ list.size());
  15. set.add(stu1);
  16. set.add(stu2);
  17. System.out.println("set size:"+ set.size());
  18. stu1.setAge(34);
  19. System.out.println("remove stu1 : "+set.remove(stu1));
  20. System.out.println("set size:"+ set.size());
  21. }
  22. }

运行结果:

stu1 == stu2 : false
stu1.equals(stu2) : true
list size:2
hashCode : 775943
hashCode : 775943
set size:1
hashCode : 776904
remove stu1 : false
set size:1

结果分析:

当我们将某个对象存到set中时,如果该对象的属性参与了hashcode的计算,那么以后就不能修改该对象参与hashcode计算的那些属性了,否则会引起意向不到的错误的。正如测试中,不能够移除stu1对象。
总结:

1、equals方法用于比较对象的内容是否相等(覆盖以后)

2、hashcode方法只有在集合中用到

3、当覆盖了equals方法时,比较对象是否相等将通过覆盖后的equals方法进行比较(判断对象的内容是否相等)。

4、将对象放入到集合中时,首先判断要放入对象的hashcode值与集合中的任意一个元素的hashcode值是否相等,如果不相等直接将该对象放入集合中。如果hashcode值相等,然后再通过equals方法判断要放入对象与集合中的任意一个对象是否相等,如果equals判断不相等,直接将该元素放入到集合中,否则不放入。

5、将元素放入集合的流程图:

6、HashSet中add方法源代码:

  1. public boolean add(E e) {
  2. return map.put(e, PRESENT)==null;
  3. }

map.put源代码:

  1. <pre name="code" class="java"> 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. modCount++;
  16. addEntry(hash, key, value, i);
  17. return null;
  18. }</pre>
  19. <pre></pre>
  20. <pre></pre>
 

hashcode和equals方法的更多相关文章

  1. 用HashSet的add方法谈hashcode和equals方法重写

    本文主要通过用HashSet的add方法讲一下hashCode和equals方法重写.错误的地方望指正. 1.了解HashSet的add方法 了解一个方法的好办法是看源码,所以先看源码 private ...

  2. Java 中正确使用 hashCode 和 equals 方法

    在这篇文章中,我将告诉大家我对hashCode和equals方法的理解.我将讨论他们的默认实现,以及如何正确的重写他们.我也将使用Apache Commons提供的工具包做一个实现. 目录: hash ...

  3. 使用hashCode()和equals()方法 - Java

    在这篇文章中,我将指出我对hashCode()和equals()方法的理解.我将讨论它们的默认实现以及如何正确地覆盖它们.我还将使用Apache Commons包中的实用工具类来实现这些方法. has ...

  4. K:java中的hashCode和equals方法

      hashCode和equals方法是Object类的相关方法,而所有的类都是直接或间接的继承于Object类而存在的,为此,所有的类中都存在着hashCode和equals.通过翻看Object类 ...

  5. 为什么要重写hashcode和equals方法?初级程序员在面试中很少能说清楚。

    我在面试 Java初级开发的时候,经常会问:你有没有重写过hashcode方法?不少候选人直接说没写过.我就想,或许真的没写过,于是就再通过一个问题确认:你在用HashMap的时候,键(Key)部分, ...

  6. 【转】 如何重写hashCode()和equals()方法

    转自:http://blog.csdn.net/neosmith/article/details/17068365 hashCode()和equals()方法可以说是Java完全面向对象的一大特色.它 ...

  7. hashcode和equals方法的区别和联系

    说到 hashcode就要和Java中的集合,HashSet,HashMap 关系最为密切. 首先附录两张Java的集合结构图: 图二:(上图的简化版) 从Set集合的特点说起 & Set是如 ...

  8. (转)Java 中正确使用 hashCode 和 equals 方法

    背景:最近在编写持久化对象时候遇到重写equals和hashCode方法的情况,对这两个方法的重写做一个总结. 链接:https://www.oschina.net/question/82993_75 ...

  9. 如何重写hashCode()和equals()方法

    hashCode()和equals()方法可以说是Java完全面向对象的一大特色.它为我们的编程提供便利的同时也带来了很多危险.这篇文章我们就讨论一下如何正解理解和使用这2个方法. 如何重写equal ...

  10. Java 重写 hashCode() 和 equals() 方法

    1. hashCode 1.1 基本概念 hashCode 是 JDK 根据对象的地址算出来的一个 int 数字(对象的哈希码值),代表了该对象再内存中的存储位置. hashCode() 方法是超级类 ...

随机推荐

  1. ambari过程中要求各个节点时间同步

    设置时间同步 控制节点机器 cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime #设置时区为北京时间,这里为上海,因为centos里面只有上海... ...

  2. S运算符&&和|| 及其优先级

    a && b : 将a, b转换为Boolean类型, 再执行逻辑与, true返回b, false返回aa || b : 将a, b转换为Boolean类型, 再执行逻辑或, tru ...

  3. 使用dotnet-dump 查找 .net core 3.0 占用CPU 100%的原因

    公司的产品一直紧跟 .net core 3.0 preview 不断升级, 部署到 Linux 服务器后, 偶尔会出现某个进程CPU占用100%. 由于服务部署在云上, 不能使用远程调试; 在局域网内 ...

  4. AJAXA进行分页(2)

    查询功能是开发中最重要的一个功能,大量数据的显示,我们用的最多的就是分页. 在ASP.NET 中有很多数据展现的控件,比如用的最多的GridView,它同时也自带了分页的功能.但是我们知道用GridV ...

  5. 九、Linux 磁盘管理

    Linux 磁盘管理 Linux磁盘管理好坏直接关系到整个系统的性能问题. Linux磁盘管理常用三个命令为df.du和fdisk. df:列出文件系统的整体磁盘使用量 du:检查磁盘空间使用量 fd ...

  6. 一道JS面试题所引发的"血案",透过现象寻本质,再从本质看现象

    觉得本人写的不算很烂的话,可以登录关注一下我的GitHub博客,新手写东西写的不好之处,还望见谅,毕竟水平有限,写东西只为交流提高,一起学习,还望大神多加指点,指出纰漏,和提出宝贵的意见,博客会坚持写 ...

  7. swoole 连接池

    proxy_pool.php <?php class ProxyServer { protected $frontends; protected $backends; /** * @var sw ...

  8. 常见react面试题汇总

    已经开源 地址:https://github.com/nanhupatar...关注我们团队: React 中 keys 的作用是什么? Keys 是 React 用于追踪哪些列表中元素被修改.被添加 ...

  9. React学习记录一

    半路出家直接上手React,其实有点吃力,所以开始研究create-react-app,从这里下手吧. create-react-app 官方网站:https://github.com/faceboo ...

  10. 使用VUE开发

    <一>VUE的开发分两种,一种是直接在HTML文件中使用,一种是VUE文件的形式开发 1,首先我们先让 HTML 文件支持 VUE 的语法指令提示 2,File -> Setting ...