1. 首先我们要理清楚为什么我们要重写equals
查看Object类种equals方法源码,被重写了这么多次,看来重写是很有必要的😼
很显然,equals的本质就是==,如果你不重写的话
- 让我们复习下 ==
基本类型:比较的是值是否相同;
引用类型:比较的是引用是否相同
- 所以为了达到值比较的效果,JDK已经是帮我们把String和Integer重写了hh
2. 那么现在我们来重写一次equals方法
场景: 假设一个User对象有以下属性
public class User {
private String username;
private String id;
private int age;
}
- 如果我们不重写equals方法,那么就算你new出的user实例各项值一样,equal的结果永远是false,正如上文说的,equals在对于引用类型的时候比较的是引用是否相同,也就是在内存中位置是否相同,hashcode同理
New一个新的对象便会开辟一个新的内存空间,那么如何重写呢?🤨
代码如下:
@Override
public boolean equals(Object obj) {
if (obj instanceof User) {
User user = (User) obj;
//这里注意age的数据类型是基础数据类型,所以用==比较
if (user.getAge() == this.age && user.getId().equals(this.id) && user.getUsername().equals(this.username)) {
return true;
}else {
return false;
}
}else {
return false;
}
}
测试结果为True
User user1 = new User("zyx", "1001", 18);
User user2 = new User("zyx", "1001", 18);
System.out.println("equals result: " + user1.equals(user2));
3. 为什么说重写equals方法后需要重写hashCode呢
- 先让我们来看看不重写hashcode会导致什么吧 代码如下:
User user1 = new User("zyx", "1001", 18);
User user2 = new User("zyx", "1001", 18);
HashMap map = new HashMap<>();
HashSet set = new HashSet<>();
System.out.println("equals result: " + user1.equals(user2));
System.out.println("user1 hashcode" + user1.hashCode());
System.out.println("user2 hashcode" + user2.hashCode());
map.put(user1, user2);
map.put(user2, user1);
set.add(user1);
set.add(user2);
//基于HashMap和HashSet的特性,我们期待的结果应该是长度均为1
System.out.println("map length:" + map.size());
System.out.println("set length:" + set.size());
打印测试结果:
- 很显然结果不如我们所料
- 这是因为HashMap、HashSet中是先判断两者hashcode是否相同,(即HashMap存储时候根据Key的hashcode决定存储位置),再使用equals作比较
代码如下:
@Override
public int hashCode() {
//这里可以调用String重写过的hashCode
int result = this.username.hashCode();
result += this.id.hashCode();
result += age;
return result;
}
打印结果:
这就是为什么重equals后还要重写hashCode😁
4. HashMap、HashSet的扩展知识
- 小记下,下次补😴