为什么重写了equals方法往往就需要重写hashCode方法?
对于hashSet数据结构,我们往往想添加我们自定义的类对象到Set集合,并实现相同内容的对象实现去重。但是并不是这样。如
public static void main(String[] args) {
List<User> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
User user = new User("1", "王二", 18);
list.add(user);
}
Set<User> set = new HashSet<>(list);
for (User user : set) {
System.out.println(user);
}
List<User> users = list.stream().distinct().collect(Collectors.toList());
System.out.println(users);
}
//去重失败,输出十个user对象。
对于hashMap的数据结构,我们可能会遇到这种情况。
public class Main {
public static void main(String[] args) {
String key1 = "a";
Map<String, Integer> map = new HashMap<>();
map.put(key1, 123);
String key2 = new String("a");
map.get(key2); // 123
System.out.println(key1 == key2); // false
System.out.println(key1.equals(key2)); // true
}
}
//为什么两个不同的字符串对象可以取到相同的value呢?
因为HashSet、HashMap底层在添加元素时,会先判断对象的hashCode是否相等,如果hashCode相等才会用equals()方法比较是否相等。HashSet和HashMap在判断两个元素是否相等时,会先判断hashCode,如果两个对象的hashCode不同则必定不相等。如果hash值相同,两个对象也不一定相同(可能产生了hash冲突),所以还需要结合equals方法进行判定。
得出:
- 哈希码不相等,则两个对象一定不相同。
- 哈希码相等,两个对象不一定相同。(可能hash冲突了)
- 两个对象相同,则哈希码和值都一定相等。
如果我们想实现自定义类作为key,并且只要对象的内容相同,我们就判定这个两个对象相同,可以取出同一个key的value.
首先就需要实现相同内容对象的hash值相等。可以采用以下方法。
publicclassPerson {
String firstName;
String lastName;
int age;
@Override
int hashCode() {
int h = 0;
h = 31 * h + firstName.hashCode();
h = 31 * h + lastName.hashCode();
h = 31 * h + age;
return h;
}
}
//基于字段的内容去实现hash算法。
那么hash值相等了之后,再equals 内容相等,就可以说这两个对象等同于Map的同一个key了。