我是靠谱客的博主 闪闪魔镜,这篇文章主要介绍java中的equals和hashCode方法以及集合的排序equals方法hashCode() 方法集合类型排序,现在分享给大家,希望可以做个参考。

equals方法

不覆写equals时候

equals() 的作用是 用来判断两个对象是否相等。

equals() 定义在JDK的Object.java中。通过判断两个对象的地址是否相等(即,是否是同一个对象)来区分它们是否相等。源码如下:
public boolean equals(Object obj) {
    return (this == obj);
}
既然Object.java中定义了equals()方法,这就意味着所有的Java类都实现了equals()方法,所有的类都可以通过equals()去比较两个对象是否相等。 但是,我们已经说过,使用默认的“equals()”方法,等价于“==”方法。
因此,我们通常会重写equals()方法:若两个对象的内容相等,则equals()方法返回true;否则,返回fasle。  
下面根据“类是否覆盖equals()方法”,将它分为2类。
(01) 若某个类没有覆盖equals()方法,当它的通过equals()比较两个对象时,实际上是比较两个对象是不是同一个对象。这时,等价于通过“==”去比较这两个对象。

(02) 我们可以覆盖类的equals()方法,来让equals()通过其它方式比较两个对象是否相等。若两个对象的内容相等,则equals()方法返回true;否则,返回fasle。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package org.senssic; public class Seh { private String name; private int age; public Seh(String name, int age) { this.age = age; this.name = name; } public static void main(String[] args) { Seh seh = new Seh("senssic", 20); Seh seh2 = new Seh("sensisc", 20); Seh seh3 = seh; // 没有覆写equals方法下,equals方法和==方法一样都是通过比较地址比较两个对象 System.out.println(seh.equals(seh2) + "--->" + (seh == seh2)); // 只能通过比较地址来判断是否同一对象 System.out.println(seh.equals(seh3) + "--->" + (seh == seh3) + "--->" + (seh2 == seh3)); } }

结果:

false--->false
true--->true--->false

因为没有覆写equals方法,所以即便对象中内容一样也是通过判断地址来比较对象的。

覆写equals时候

覆写equals方法的步骤
1.比较地址,如果地址相同,肯定是同一对象
2.如果比较的对象为null直接返回false
3.比较类的字节码
4.向下类型转换比较属性
5.比较属性
如果是基本属性(除去浮点数)直接判断是否相等
如果是double类型通过doubleToLongBits方法转换为long类型再比较
如果是float类型通过floatToIntBits方法转换为int类型再比较
如果是引用对象先判断是否为空,再调用其对应的equals方法

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package org.senssic; public class Seh { private String name; private int age; private byte byt; private short shot; private long lo; private char ch; private boolean bool; private float fl; private double dou; @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Seh other = (Seh) obj; if (age != other.age) return false; if (bool != other.bool) return false; if (byt != other.byt) return false; if (ch != other.ch) return false; if (Double.doubleToLongBits(dou) != Double.doubleToLongBits(other.dou)) return false; if (Float.floatToIntBits(fl) != Float.floatToIntBits(other.fl)) return false; if (lo != other.lo) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; if (shot != other.shot) return false; return true; } public Seh(String name, int age) { this.age = age; this.name = name; } public static void main(String[] args) { Seh seh = new Seh("senssic", 20); Seh seh2 = new Seh("senssic", 20); Seh seh3 = seh; // 覆写equals方法下,equals方法和==方法一样不一样equals比较同一对象,==比较地址 System.out.println(seh.equals(seh2) + "--->" + (seh == seh2)); // 只能通过equals方法来比较是否同一对象 System.out.println(seh.equals(seh3) + "--->" + (seh == seh3) + "--->" + (seh2 == seh3)); } }
结果:

true--->false
true--->true--->false
覆写了equals方法后如果两个对象的属性都相等,则返回true

java对equals()的要求。有以下几点:
1. 对称性:如果x.equals(y)返回是"true",那么y.equals(x)也应该返回是"true"。
2. 反射性:x.equals(x)必须返回是"true"。
3. 类推性:如果x.equals(y)返回是"true",而且y.equals(z)返回是"true",那么z.equals(x)也应该返回是"true"。
4. 一致性:如果x.equals(y)返回是"true",只要x和y内容一直不变,不管你重复x.equals(y)多少次,返回都是"true"。
5. 非空性,x.equals(null),永远返回是"false";x.equals(和x不同类型的对象)永远返回是"false"。

 equals() 与 == 的区别

== : 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不试同一个对象。
equals() : 它的作用也是判断两个对象是否相等。但它一般有两种使用情况:
                 情况1,类没有覆盖equals()方法。则通过equals()比较该类的两个对象时,等价于通过“==”比较这两个对象。
                 情况2,类覆盖了equals()方法。一般,我们都覆盖equals()方法来两个对象的内容相等;若它们的内容相等,则返回true(即,认为这两个对象相等)。

hashCode() 方法

hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。
hashCode() 定义在JDK的Object.java中,这就意味着Java中的任何类都包含有hashCode() 函数。
       虽然,每个Java类都包含hashCode() 函数。但是,仅仅当创建并某个“类的散列表”(关于“散列表”见下面说明)时,
       该类的hashCode() 才有用(作用是:确定该类的每一个对象在散列表中的位置;其它情况下(例如,创建类的单个对象,或者创建类的对象数组等等),
       类的hashCode() 没有作用。
       上面的散列表,指的是:Java集合中本质是散列表的类,如HashMap,Hashtable,HashSet。
       也就是说:hashCode() 在散列表中才有用,在其它情况下没用。在散列表中hashCode() 的作用是获取对象的散列码,进而确定该对象在散列表中的位置。
比如HashSet是Set集合,为了快速的定位里面的元素,就需要用到散列码确定,然后进行操作。当然如果发现其对应的hash表中有相同的hash值,只保存一个。

set判断不同对象的顺序:1>通过hashCode()的值快速比较,如果hash值不相等,判定他们不同;
                                             2>如果hashCode相等,就比较equals()
                                              如果equals()相等,就判定这两个对象相等,否则不相等

若两个元素相等,它们的散列码一定相等;但反过来确不一定。在散列表中,
 1、如果两个对象相等,那么它们的hashCode()值一定要相同;

 2、如果两个对象hashCode()相等,它们并不一定相等。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package org.senssic; public class Seh { private final String name; private final int age; private byte byt; private short shot; private long lo; private char ch; private boolean bool; private float fl; private double dou; // Objec中的hashCode()方法是native方法,由本地代码自动生成,如果不覆写hashCode则由native代码生成一个hash值 @Override public int hashCode() { // 之所以选择31,是因为它是个奇素数,如果乘数是偶数,并且乘法溢出的话, // 信息就会丢失,因为与2相乘等价于移位运算。使用素数的好处并不是很明显 // ,但是习惯上都使用素数来计算散列结果。31有个很好的特性,就是用移位和减法来代替乘法, // 可以得到更好的性能:31*i==(i<<5)-i。现在的VM可以自动 //完成这种优化。 final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + (bool ? 1231 : 1237);// 1231 1237都是素数 result = prime * result + byt; result = prime * result + ch; long temp; temp = Double.doubleToLongBits(dou); result = prime * result + (int) (temp ^ (temp >>> 32)); result = prime * result + Float.floatToIntBits(fl); result = prime * result + (int) (lo ^ (lo >>> 32)); result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + shot; return result; } public Seh(String name, int age) { this.age = age; this.name = name; } public static void main(String[] args) { Seh seh = new Seh("senssic", 21); Seh seh2 = new Seh("senssic", 21); // 虽然两个对象的hash值相等但此对象并不相等,所以:对象相等hash值一定相同,hash值相等对象不一定相等 System.out.println(seh.hashCode() + "--->" + seh2.hashCode()); } }


集合类型排序

Java API针对集合类型排序提供了两种支持:
第一个方法要求所排序的元素类必须实现java.lang.Comparable接口。
第二个方法要求实现一个java.util.Comparator接口,需要写个额外的排序类还指定排序方法。

1.实现Comparable接口

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package org.senssic; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; public class Person implements Comparable<Person> { private String name; private int age; private int score; private int english; public Person(String name, int age, int score, int english) { this.name = name; this.age = age; this.score = score; this.english = english; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + english; result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + score; return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Person other = (Person) obj; if (age != other.age) return false; if (english != other.english) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; if (score != other.score) return false; return true; } // 1表示大于0表示等于-1表示小于 @Override public int compareTo(Person p) { if (this.age > p.age) {// 如果年龄大于直接排序按年龄 return -1; } else if (this.score > p.score) {// 如果年龄小于或等于再比较分数按分数高低排 return 1; } else {// 如果年龄小于且分数小于等于按英语成绩排 if (this.english > p.english) { return 1; } else if (this.english < p.english) { return -1; } else { return 0; } } } @Override public String toString() { // TODO Auto-generated method stub return "名字:" + this.name; } public static void main(String[] args) { Person param = new Person("senssic", 12, 23, 45); Person person = new Person("qiyu", 12, 23, 41); Person perso = new Person("zhangsan", 12, 21, 41); Person pers = new Person("zhaosi", 13, 21, 41); // 使用list List<Person> list = new ArrayList<>(); list.add(param); list.add(pers); list.add(perso); list.add(person); Collections.sort(list);// 集合工具类排序list for (Person per : list) { System.out.println(per.toString()); } // 使用set Set<Person> set = new TreeSet<>();// 因为treeSet是唯一实现SortedSet接口,可以自动实现排序,但是效率低些 set.add(param); set.add(pers); set.add(perso); set.add(person); System.out.println(set.size() + "--->" + perso.equals(param) + perso.equals(pers) + perso.equals(person)); for (Person p : set) { System.out.println(p.toString()); // 此处只有三个输出因为:TreeSet判断两个对象不相等的标准是:两个对象通过equals方法比较返回false, // 或通过compareTo(Object // obj)比较没有返回0——即使两个对象时同一个对象,TreeSet也会把它们当成两个对象进行处理。 // 因为上面的param和perso比较时候没有返回0所以认为是同一个对象,如果使用hashSet就会有四个输出。 } // 使用map Map<Person, String> map = new TreeMap<Person, String>();// 通过二叉树算法,可以自动实现排序,但是效率低些 map.put(pers, "中国"); map.put(perso, "安徽"); map.put(param, "池州"); map.put(person, "阜阳"); for (Entry<Person, String> mapEntry : map.entrySet()) { System.out .println(mapEntry.getKey() + "--->" + mapEntry.getValue()); // 此处输出的也为三个,比较对象相同方法同TreeSet一样 } } }


2.实现Comparator接口

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package org.senssic; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; class PersonComper implements Comparator<Person> { @Override public int compare(Person p, Person per) { if (p.getAge() > per.getAge()) {// 如果年龄大于直接排序按年龄 return -1; } else if (p.getScore() > per.getScore()) {// 如果年龄小于或等于再比较分数按分数高低排 return 1; } else {// 如果年龄小于且分数小于等于按英语成绩排 if (p.getEnglish() > per.getEnglish()) { return 1; } else if (p.getEnglish() < per.getEnglish()) { return -1; } else { return 0; } } } } public class Person { private String name; private int age; private int score; private int english; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public int getScore() { return score; } public void setScore(int score) { this.score = score; } public int getEnglish() { return english; } public void setEnglish(int english) { this.english = english; } public Person(String name, int age, int score, int english) { this.name = name; this.age = age; this.score = score; this.english = english; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + english; result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + score; return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Person other = (Person) obj; if (age != other.age) return false; if (english != other.english) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; if (score != other.score) return false; return true; } @Override public String toString() { // TODO Auto-generated method stub return "名字:" + this.name; } public static void main(String[] args) { Person param = new Person("senssic", 12, 23, 45); Person person = new Person("qiyu", 12, 23, 41); Person perso = new Person("zhangsan", 12, 21, 41); Person pers = new Person("zhaosi", 13, 21, 41); // 使用list List<Person> list = new ArrayList<>(); list.add(param); list.add(pers); list.add(perso); list.add(person); PersonComper pComper = new PersonComper(); Collections.sort(list, pComper);// 集合工具类排序list for (Person per : list) { System.out.println(per.toString()); } // 使用set Set<Person> set = new TreeSet<>(pComper);// 使用TreeSet的构造方法传入Comparator的接口实现,因为treeSet是唯一实现SortedSet接口,可以自动实现排序,但是效率低些 set.add(param); set.add(pers); set.add(perso); set.add(person); System.out.println(set.size() + "--->" + perso.equals(param) + perso.equals(pers) + perso.equals(person)); for (Person p : set) { System.out.println(p.toString()); // 此处只有三个输出因为:TreeSet判断两个对象不相等的标准是:两个对象通过equals方法比较返回false, // 或通过compareTo(Object // obj)比较没有返回0——即使两个对象时同一个对象,TreeSet也会把它们当成两个对象进行处理。 // 因为上面的param和perso比较时候没有返回0所以认为是同一个对象,如果使用hashSet就会有四个输出。 } // 使用 map Map<Person, String> map = new TreeMap<>(pComper);// 使用TreeSet的构造方法传入Comparator的接口实现,可以自动实现排序,但是效率低些 map.put(pers, "中国"); map.put(perso, "安徽"); map.put(param, "池州"); map.put(person, "阜阳"); for (Entry<Person, String> mapenEntry : map.entrySet()) { System.out.println(mapenEntry.getKey() + "--->" + mapenEntry.getValue()); // 此处输出的也为三个,比较对象相同方法同TreeSet一样 } } }




最后

以上就是闪闪魔镜最近收集整理的关于java中的equals和hashCode方法以及集合的排序equals方法hashCode() 方法集合类型排序的全部内容,更多相关java中的equals和hashCode方法以及集合的排序equals方法hashCode()内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(81)

评论列表共有 0 条评论

立即
投稿
返回
顶部