转自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. CentOS启动时自动加载内核模块

    要想在CentOS中自动加载内核模块,需要在/etc/sysconfig/modules/目录中增加一个脚本,在此脚本中加载所需的模块. 下面是我所用的一个名为8021q.modules的脚本,用来在 ...

  2. axios跨域问题记录

    axios({headers: {'X-Requested-With': 'XMLHttpRequest','Content-Type': 'application/json; charset=UTF ...

  3. 方法 -------JavaScript

    本文摘要:http://www.liaoxuefeng.com/ 在一个对象中绑定函数,称为这个对象的方法. 在JavaScript的中,对象的定义是这样的: var xiaoming = { nam ...

  4. 使用git stash命令保存和恢复进度

    使用git stash命令保存和恢复进度 git stash 保存当前工作进度,会把暂存区和工作区的改动保存起来.执行完这个命令后,在运行git status命令,就会发现当前是一个干净的工作区,没有 ...

  5. 绘制圆形 和 椭圆形:边圆形 imageellipse() 、 填充圆形imagefilledellipse()

    <?php //1. 绘制图像资源(创建一个画布) $image = imagecreatetruecolor(500, 300); //2. 先分配一个绿色 $green = imagecol ...

  6. DeepFaceLab进阶(4):通过Colab免费使用Tesla K80 跑模型!

    当学会了换脸软件DeepFaceLab基本使用,各种参数配置,各有优化技能之后.唯一约束你的可能是电脑配置. CPU能跑,但是慢到怀疑人生,低配模型都得跑一周 低配显卡,显存不够,H128 根本就跑不 ...

  7. javascript sprintf方法

    转载自: http://demon.tw/programming/javascript-sprintf.html function str_repeat(i, m) { for (var o = [] ...

  8. 精通SpringBoot---整合RabbitMQ消息队列

    今天来和朋友们一起学习下,SpringBoot怎么整合RabbitMQ.目前消息组件大致有三种:.activemq, rabbitmq, kafka.这三者各有优缺点,RabbitMQ相比之下是处于其 ...

  9. Hie with the Pie POJ - 3311

    Hie with the Pie POJ - 3311 The Pizazz Pizzeria prides itself in delivering pizzas to its customers ...

  10. docker 学习(2)

    docker容器中安装vim ubuntu 中默认未装vim,docker run ubuntu vim 出现: container_linux.go:247: starting container ...