http://blog.csdn.net/afgasdg/article/details/6889383

一、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. 对hashcode、equals的理解

    1.首先hashcode和equals都是java每个对象都存在的方法,因为他们两是Object的方法. 2.hashcode方法默认返回的是该对象内存地址的哈希码,然而你会发现,Object类中没有 ...

  2. java中hashcode()和equals()的详解

    今天下午研究了半天hashcode()和equals()方法,终于有了一点点的明白,写下来与大家分享(zhaoxudong 2008.10.23晚21.36). 1. 首先equals()和hashc ...

  3. Java hashCode() 和 equals()的若干问题

    原文:http://www.cnblogs.com/skywang12345/p/3324958.html 本章的内容主要解决下面几个问题: 1 equals() 的作用是什么? 2 equals() ...

  4. java中的hashcode()和equals()

    equals()和hashcode()都继承自object类. equals() equals()方法在object类中定义如下: public boolean equals(Object obj) ...

  5. Java hashCode() 和 equals()的若干问题解答

    本章的内容主要解决下面几个问题: 1 equals() 的作用是什么? 2 equals() 与 == 的区别是什么? 3 hashCode() 的作用是什么? 4 hashCode() 和 equa ...

  6. 【Java】Map杂谈,hashcode()、equals()、HashMap、TreeMap、LinkedHashMap、ConcurrentHashMap

    参考的优秀文章: <Java编程思想>第四版 <Effective Java>第二版 Map接口是映射表的结构,维护键对象与值对象的对应关系,称键值对. > hashco ...

  7. 【Java】hashcode()和equals()

    大家知道,在集合中判断集合中的两个元素是否相同,依赖的是hashcode()和equals()两个方法. > 一个简单的实验 public class Teacher { private Int ...

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

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

  9. Maintainable HashCode and Equals Using Apache Commons

    Java hashCode and equals methods can be tricky to implement correctly. Fortunately, all majors IDEs ...

  10. Java中hashcode,equals和==

    hashcode方法返回该对象的哈希码值. hashCode()方法可以用来来提高Map里面的搜索效率的,Map会根据不同的hashCode()来放在不同的位置,Map在搜索一个对象的时候先通过has ...

随机推荐

  1. Python 类的名称空间和组合

    一.Python类的名称空间 class Student(object): School = '北京大学' def __init__(self): pass stu1 = Student() stu1 ...

  2. 基于TCP协议的聊天室控制台版

    我之前写过一篇博客,主要是基于TCP协议实现的聊天室swing版,在此再写一个基于TCP协议实现的聊天室控制台版,便于学习和比较. package 聊天室console版.utils; import ...

  3. Error -27796: Failed to connect to server "ip地址": [10060] Connection timed out

    如果出现Error -27796: Failed to connect to server "ip地址": [10060] Connection timed out 这样的错误,如 ...

  4. 后门技术和Linux LKM Rootkit详解

    2010-01-15 10:32 chinaitlab chinaitlab 字号:T | T 在这篇文章里, 我们将看到各种不同的后门技术,特别是 Linux的可装载内核模块(LKM). 我们将会发 ...

  5. fprintf输出到文件中,sprintf输出到字符串中. 如: fprintf(fp,"%s",name); fp为文件指针 sprintf(buff,"%s",name); buff为字符数组

    fprintf输出到文件中,sprintf输出到字符串中. 如: fprintf(fp,"%s",name); fp为文件指针 sprintf(buff,"%s" ...

  6. 构建最基础的Spring项目及所需要的jar包

    1.Spring 框架由6个模块组成 上图是spring4的结构图,不同版本结构略有差异,但模块都是相同的. 2.Core Container 核心容器 容器是Spring的核心部分,Core Con ...

  7. OPENSSL问题,使用fsockopen()函数提示错误

    环境配置 系统环境 CentOS7.2WDCP v3.2.2 lanmp PHP 多版本 指定使用5.6 OpenSSL 1.0.2h  3 May 2016 php.ini相关设置allow_url ...

  8. 获取对象的key【键】和分别获取数组的key【键】和值

    一.先说对象,如何获取key[键]: var obj={ name:"websong", qq:289483936 } 想要获取这个obj对象的键“name”和"qq&q ...

  9. Python全栈开发之3、数据类型set补充、深浅拷贝与函数

    转载请注明出处http://www.cnblogs.com/Wxtrkbc/p/5466082.html 一.基本数据类型补充 set是一个无序而且不重复的集合,有些类似于数学中的集合,也可以求交集, ...

  10. 用LR录制文件下载并随机产生文件名

    用LR录制文件下载并随机产生文件名 {H.IY:X.Tn0 8h&~-D|6fV0Action()51Testing软件测试网GE$nV}s,R{51Testing软件测试网 }9sUS'q  ...