一些集合如HashMap,HashSet等等,equals和hashcode在这些集合当中都有很重要的作用,如插入元素用涉及到hashcode,查找元素涉及到equals。
下面来讲一个小例子,加入存储一个(用户名,小区名)这样的一个map,代码很简单
class Student {
private String name;
Student(String name) {
this.name = name;
}
}
public class Main {
public static void main(String[] args) {
Student jack = new Student("jack");
HashMap room = new HashMap();
room.put(jack,"幸福小区");
System.out.println(room.get(new Student("jack")));
}
}
输出结果:
null
现在我们希望查找一个jack住的小区,通过map.get方法,没有重写hashcode和equals的情况下,输出结果为null。再来重写下hashcode和equals方法
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
输出结果:
幸福小区
可以看到这样就可以正确的查找出来了,接下来我们来寻找原因.
对于我们人来说,Student stu1 = new Student("jack");Student stu2 = new Student("jack");我们知道默认情况下,虚拟机中因为stu1 和stu2 地址不同,他们通过equals方法得到的是false,不过对于我们来说,显然希望名字叫做jack的对象相等的,既然我们希望他们相等,在java中,如果两个对象相等,那么他们的hashcode一定要相等点击这里看官方文档
If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
如果不重写,默认的hashcode是不相等的。
我们来看下HashMap中put和get方法
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
可以看到在put中使用了hashcode,再来看下get
public V get(Object key) {
Node e;
return (e = getNode(hash(key), key)) == null ? null : e.value;
}
final Node getNode(int hash, Object key) {
Node[] tab; Node first, e; int n; K k;
if ((tab = table) != null && (n = tab.length) > 0 &&
(first = tab[(n - 1) & hash]) != null) {
if (first.hash == hash && // always check first node
((k = first.key) == key || (key != null && key.equals(k))))
return first;
if ((e = first.next) != null) {
if (first instanceof TreeNode)
return ((TreeNode)first).getTreeNode(hash, key);
do {
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
} while ((e = e.next) != null);
}
}
return null;
}
上面代码较长且难懂,如果没有看过hashcode源码的客观直接跳过,看道理那里的equals,自然可以发现在get中使用了equals方法。Hashcdoe方法决定了元素在哈希表中存放的地方,equals决定了从哪里取出来,因此我们在定以一个类的时候一定要记得重写hashcode和equals