hashcode和equals方法的区别和联系

简介:

说到 hashcode就要和Java中的集合,HashSet,HashMap 关系最为密切。

首先附录两张Java的集合结构图:

图二:(上图的简化版)

 

从Set集合的特点说起 & Set是如何去除重复元素的:

Set:元素不可以重复,是无序的。 Set接口中的方法和Collection一致(看上面的集合框架图)。

  |--HashSet: 内部数据结构是哈希表 ,是不同步的。

如何保证该集合的元素唯一性呢?

是通过对象的hashCode和equals方法来完成对象唯一性的。
hashCode值和对象的内容是存储在hash表中的。 如果对象的hashCode值不同,那么不用判断equals方法,就直接存储到哈希表中。 如果对象的hashCode值相同,那么要再次判断对象的equals方法是否为true。 如果为true,视为相同元素,不存储。如果为false,那么视为不同元素,就进行存储

记住:如果元素要存储到HashSet集合中,必须覆盖hashCode方法和equals方法。一般情况下,如果定义的类会产生很多对象,比如人(Person类),学生(Student类),书(Book类),通常都需要覆盖equalshashCode方法。

建立对象判断是否相同的依据。

 

哈希算法是底层windows做的,而且针对不同的对象有不同的哈希算法运算。

java类中有的哈希算法是native用的windows底层 的,有的根据对象的不同进行了重写。

哈希表:哈希这种算法会算出很多的值,把这些值存储起来形成一个表。表中有对应关系。

哈希表的结构还是数组。只是哈希这种算法对数组进行了优化。

哈希算法有一种最常见的算法就是取余。

 

哈希表中不能有重复的元素。

哈希表是如何判断元素是否是重复的? 举例一种取余的HashCode算法原理:

 

ab”和”ba”产生的哈希值是一样的,取余之后都是5,但是内容不一样,哈希值对这样的情况也有对应的方法,在5角标出“挂”一个”ba”。

 

list集合removecontains都要判断相不相同,都是用的equals,不用hashcode

如果到了Set集合,要删除一个元素,要依据该元素是否和该容器中的元素是否相同。HashSet依据对象的hashcodeequals

代码举例,Set中存储自定义的类对象:

 ①原始的方式,不重写equals也不重写hashcode。

 Person.java

复制代码
 1 public class Person {
 2     private String name;
 3     private int age;
 4     public String getName() {
 5         return name;
 6     }
 7     public void setName(String name) {
 8         this.name = name;
 9     }
10     public int getAge() {
11         return age;
12     }
13     public void setAge(int age) {
14         this.age = age;
15     }
16     public Person(String name, int age) {
17         super();
18         this.name = name;
19         this.age = age;
20     }
21 }
复制代码

CollectionTest.java

复制代码
 1 import java.util.ArrayList;
 2 import java.util.HashMap;
 3 import java.util.HashSet;
 4 import java.util.Iterator;
 5 import java.util.Map;
 6 import java.util.Map.Entry;
 7 import java.util.Set;
 8 public class CollectionTest {
 9     public static void main(String[] args) {
10         //单个对象
11         Person p1 = new Person("kxh",22);
12         Person p2 = new Person("kxh",22);
13         System.out.println("p1 == p2:" + (p1 == p2));
14         System.out.println("p1.equals(p2):" + p1.equals(p2));
15         //List集合
16         ArrayList<Person> arrayList = new ArrayList<Person>();
17         arrayList.add(new Person("lisi1",11));
18         arrayList.add(new Person("lisi2",12));
19         arrayList.add(new Person("lisi3",13));
20         arrayList.add(new Person("lisi4",14));
21         arrayList.add(new Person("lisi4",14));
22         //HashMap集合
23         HashMap<Person,Object> hashMap = new HashMap<Person,Object>();
24         hashMap.put(new Person("lisi1",11),new Object());
25         hashMap.put(new Person("lisi2",12),new Object());
26         hashMap.put(new Person("lisi3",13),new Object());
27         hashMap.put(new Person("lisi4",14),new Object());
28         hashMap.put(new Person("lisi4",14),new Object());
29         //HashSet集合
30         HashSet<Person> hashSet = new HashSet<Person> ();
31         hashSet.add(new Person("lisi1",11));
32         hashSet.add(new Person("lisi2",12));
33         hashSet.add(new Person("lisi3",13));
34         hashSet.add(new Person("lisi4",14));
35         hashSet.add(new Person("lisi4",14));
36 
37         //遍历ArrayList集合
38         System.out.println("遍历ArrayList集合------");
39         Iterator arrayListIterator = arrayList.iterator();
40         while(arrayListIterator.hasNext()){
41             Person p = (Person) arrayListIterator.next();
42             System.out.println(p.getName()+"---"+p.getAge());
43         }
44         
45         //遍历HashMap集合
46         System.out.println("遍历HashMap集合------");
47         Set<Entry<Person, Object>> entrySet = hashMap.entrySet();
48         Iterator entrySetIterator = entrySet.iterator();
49         while(entrySetIterator.hasNext()){
50             Map.Entry entry = (Map.Entry)entrySetIterator.next();
51             System.out.println(entry.getKey()+"---"+entry.getValue());
52         }
53         
54         //遍历HashSet集合
55         System.out.println("遍历HashSet集合------");
56         Iterator hashSetIterator = hashSet.iterator();
57         while(hashSetIterator.hasNext()){
58             Person p = (Person) hashSetIterator.next();
59             System.out.println(p.getName()+"---"+p.getAge());
60         }
61     }
62 }
复制代码

 程序输出:

复制代码
p1 == p2:false
p1.equals(p2):false
遍历ArrayList集合------
lisi1---11
lisi2---12
lisi3---13
lisi4---14
lisi4---14
遍历HashMap集合------
cn.cdv.collection.Person@52e922---java.lang.Object@1b84c92
cn.cdv.collection.Person@10dea4e---java.lang.Object@1c7c054
cn.cdv.collection.Person@1db9742---java.lang.Object@12204a1
cn.cdv.collection.Person@106d69c---java.lang.Object@a298b7
cn.cdv.collection.Person@25154f---java.lang.Object@14991ad
遍历HashSet集合------
lisi1---11
lisi2---12
lisi4---14
lisi4---14
lisi3---13
复制代码

ArrayList中可以存储重复元素,HashMap中使用了两个“一样的”new Person("lisi4",14)作为key,同一个key在HashMap中只能有一个,HashSet中存储进去了两个lisi4 14”又是集合Set Set集合中不会再存储相同的元素。为什么出现这种情况。

  ①这是Map和Set存储用户自定义对象。

  ②Person类继承的是Objectnew一个Person都有不同的地址值,hashcode不同,对于Set集合来说是不同的元素,对Map来说是不同的Key。

  ③你自己定义的只要名字和年龄一样就是不同的对象这个规则程序现在是不知道的。需要你自己去定义,完善。

 

②只重写equals方法,在equals方法中判断Person对象的name和age属性值是否相等来判断对象是否相同。

复制代码
 1 public class Person extends Object {
 2     private String name;
 3     private int age;
 4     public String getName() {
 5         return name;
 6     }
 7     public void setName(String name) {
 8         this.name = name;
 9     }
10     public int getAge() {
11         return age;
12     }
13     public void setAge(int age) {
14         this.age = age;
15     }
16     public Person(String name, int age) {
17         super();
18         this.name = name;
19         this.age = age;
20     }
21     
22     @Override
23     public boolean equals(Object obj) {
24         if(this == obj){//当判断完hashCode()方法之后hah值相同,如果内容也相同,使用==这样结束equals语句中的判断。
25             return true;
26         }
27         if(!(obj instanceof Person)){
28             throw new ClassCastException("类型错误");
29         }
30         //运行到这里说明两者 相等,打印输出。。。
31         System.out.println(this+"....重写equals判断相同....."+obj);
32         Person p = (Person)obj;
33         return this.name.equals(p.name) && this.age == p.age;
34     }
35     
36     public String toString(){
37         return name +":"+ age;
38     }
39 }
复制代码

 程序输出:

复制代码
p1 == p2:false
kxh:22....重写equals判断相同.....kxh:22
p1.equals(p2):true
遍历ArrayList集合------
lisi1---11
lisi2---12
lisi3---13
lisi4---14
lisi4---14
遍历HashMap集合------
lisi3:13---java.lang.Object@1b84c92
lisi4:14---java.lang.Object@1c7c054
lisi1:11---java.lang.Object@12204a1
lisi2:12---java.lang.Object@a298b7
lisi4:14---java.lang.Object@14991ad
遍历HashSet集合------
lisi1---11
lisi2---12
lisi4---14
lisi4---14
lisi3---13
复制代码

结果分析:因为Person两个对象的age和name属性相等,而且又是通过覆盖equals方法来判断的,所示p1.equals(p2) 为true。

只重写equals方法,加入ArrayList,HashMap和HashSet的元素都全部打印出来。

 

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

复制代码
 1 public class Person extends Object {
 2     private String name;
 3     private int age;
 4     public String getName() {
 5         return name;
 6     }
 7     public void setName(String name) {
 8         this.name = name;
 9     }
10     public int getAge() {
11         return age;
12     }
13     public void setAge(int age) {
14         this.age = age;
15     }
16     public Person(String name, int age) {
17         super();
18         this.name = name;
19         this.age = age;
20     }
21     
22     /*
23      * hashCode()方法返回的是一个int类型的值,这里根据Person类对象的特点,
24      * 返回一个由name和age属性决定的值最合适。age之后乘以的数字只要不是1,都可以。
25      */
26     @Override
27     public int hashCode() {
28         System.out.println(this+".......hashCode的值:" + name.hashCode()+age*27);
29         return name.hashCode()+age*27;
30     }
31     
32     public String toString(){
33         return name +":"+ age;
34     }
35 }
复制代码

 测试类不变,运行测试类,程序输出:

复制代码
p1 == p2:false
p1.equals(p2):false
lisi1:11.......hashCode的值:102982142297
lisi2:12.......hashCode的值:102982143324
lisi3:13.......hashCode的值:102982144351
lisi4:14.......hashCode的值:102982145378
lisi4:14.......hashCode的值:102982145378
lisi1:11.......hashCode的值:102982142297
lisi2:12.......hashCode的值:102982143324
lisi3:13.......hashCode的值:102982144351
lisi4:14.......hashCode的值:102982145378
lisi4:14.......hashCode的值:102982145378
遍历ArrayList集合------
lisi1---11
lisi2---12
lisi3---13
lisi4---14
lisi4---14
遍历HashMap集合------
lisi2:12---java.lang.Object@1db9742
lisi1:11---java.lang.Object@106d69c
lisi4:14---java.lang.Object@52e922
lisi4:14---java.lang.Object@25154f
lisi3:13---java.lang.Object@10dea4e
遍历HashSet集合------
lisi2---12
lisi1---11
lisi4---14
lisi4---14
lisi3---13
复制代码

上面ArrayList,HashMap,HashSet总共三组,但是只打印了两组数据的hashcode。由集合的特性可知,这两组是HashMap和HashSet添加数据时打印的,ArrayList中添加数据是不会判断hashcode值的。

我们并没有覆盖equals方法只覆盖了hashCode方法,对于HashMap两个对象中有两个new Person("lisi4",14)作为key,对于HashSet中放入有两个new Person("lisi4",14),

虽然两个对象new Person("lisi4",14)的hashCode一样,但是根据比较原则,先比较hashcode,如果hashcode相同再比较equals,很明显两个new Person("lisi4",14) 对应的值为false,所以加入到HashMap和HashSet的值全部打印出来。

 ④既覆盖hashCode() 又重写equals()方法

复制代码
 1 public class Person extends Object {
 2     private String name;
 3     private int age;
 4     public String getName() {
 5         return name;
 6     }
 7     public void setName(String name) {
 8         this.name = name;
 9     }
10     public int getAge() {
11         return age;
12     }
13     public void setAge(int age) {
14         this.age = age;
15     }
16     public Person(String name, int age) {
17         super();
18         this.name = name;
19         this.age = age;
20     }
21     
22     /*
23      * hashCode()方法返回的是一个int类型的值,这里根据Person类对象的特点,
24      * 返回一个由name和age属性决定的值最合适。age之后乘以的数字只要不是1,都可以。
25      */
26     @Override
27     public int hashCode() {
28         System.out.println(this+".......hashCode的值:" + name.hashCode()+age*27);
29         return name.hashCode()+age*27;
30     }
31 
32     @Override
33     public boolean equals(Object obj) {
34         if(this == obj){//当判断完hashCode()方法之后hah值相同,如果内容也相同,使用==这样结束equals语句中的判断。
35             return true;
36         }
37         if(!(obj instanceof Person)){
38             throw new ClassCastException("类型错误");
39         }
40         //运行到这里说明两者 相等,打印输出。。。
41         System.out.println(this+"....重写equals判断相同....."+obj);
42         Person p = (Person)obj;
43         return this.name.equals(p.name) && this.age == p.age;
44     }
45     
46     public String toString(){
47         return name +":"+ age;
48     }
49 }
复制代码

 测试类不变,运行输出:

复制代码
p1 == p2:false
kxh:22....重写equals判断相同.....kxh:22
p1.equals(p2):true
lisi1:11.......hashCode的值:102982142297
lisi2:12.......hashCode的值:102982143324
lisi3:13.......hashCode的值:102982144351
lisi4:14.......hashCode的值:102982145378
lisi4:14.......hashCode的值:102982145378
lisi4:14....重写equals判断相同.....lisi4:14
lisi1:11.......hashCode的值:102982142297
lisi2:12.......hashCode的值:102982143324
lisi3:13.......hashCode的值:102982144351
lisi4:14.......hashCode的值:102982145378
lisi4:14.......hashCode的值:102982145378
lisi4:14....重写equals判断相同.....lisi4:14
遍历ArrayList集合------
lisi1---11
lisi2---12
lisi3---13
lisi4---14
lisi4---14
遍历HashMap集合------
lisi2:12---java.lang.Object@1db9742
lisi1:11---java.lang.Object@106d69c
lisi4:14---java.lang.Object@52e922
lisi3:13---java.lang.Object@25154f
遍历HashSet集合------
lisi2---12
lisi1---11
lisi4---14
lisi3---13
复制代码

 通过结果可以看出,hashcode和equals都复写之后才真正保证了唯一性,复写equals方法必须复写hashcode方法。


本文转自SummerChill博客园博客,原文链接:http://www.cnblogs.com/DreamDrive/p/7505464.html,如需转载请自行联系原作者

相关文章
|
6月前
|
存储 算法 Java
为什么要重写 hashcode 和 equals 方法
为什么要重写 hashcode 和 equals 方法
54 0
|
4月前
|
Java 容器
equals与hashcode的区别与联系
equals与hashcode的区别与联系
|
6月前
|
存储 Java 对象存储
当hashCode相同时,equals是否也相同?
当hashCode相同时,equals是否也相同?
33 0
|
6月前
|
存储 Java
为什么要重写hashCode()和equals()(深入了解)
为什么要重写hashCode()和equals()(深入了解)
|
算法 Java 索引
equals方法和hashCode方法之间的那些事(1.1)
equals方法和hashCode方法之间的那些事(1.1)
为什么要重写 hashcode 和 equals 方法?
为什么要重写 hashcode 和 equals 方法?
79 0
|
存储 Java
“==”和equals 最大的区别
“==”和equals 最大的区别是 “==”是运算符,如果是基本数据类型,则比较存储的值;如果是引用数据类型,则比较所指向对象的地址值。 equals是Object的方法,比较的是所指向的对象的地址值,一般情况下,重写之后比较的是对象的值。
|
存储 Java
详解“==”和equals的区别
“==”和equals 最大的区别是 “==”是运算符,如果是基本数据类型,则比较存储的值;如果是引用数据类型,则比较所指向对象的地址值。 equals是Object的方法,比较的是所指向的对象的地址值,一般情况下,重写之后比较的是对象的值。
|
存储
"=="和 equals 方法究竟有什么区别?
"=="和 equals 方法究竟有什么区别?
126 0
|
存储 缓存 Java
深入理解= = 、equals()与hashcode()的关系
理解= = 、equals()与hashcode()的关系
107 0
深入理解= = 、equals()与hashcode()的关系