equals()方法和hashCode()方法
equals()和hashCode()方法的关联,以前看明白了,过段时间又忘了,现在记录一下.
先回顾一下
equals()方法
equals()方法是Object类里面的,比较的是两个对象在内存中的首地址,源码如下
public boolean equals(Object obj) {
return (this == obj);
}
如果比较我们自己的对象,就需要重写equals()方法.
比如:
@Override
public boolean equals(Object o) {
if(this == o) {
return true;
}
if(!(o instanceof Student)) {
return false;
}
Student temp = (Student)o;
return this.getName().equals(temp.getName()) && this.getAge() == temp.getAge() && this.getGrade().equals(temp.getGrade());
}
主意 @Override 注解不能少,因为它会帮助进行我们校验,防止写错.
其实到这一步就行了,两个对象就可以按照我们的需要来比较了.
hashCode()方法
hashCode()方法的返回值是散列表中用到的,也就是HashMap,Set等数据结构里面用到,如果我们创建的类不会在这些数据结构中使用,可以不重写hashCode()方法.
根据 Object 规范,如果两个对象的 equals() 方法返回true,那么这两个对象的 hashCode() 方法返回值一定相同;
如果两个对象的 equals() 方法返回false,那么它们的 hashCode() 方法返回值可以不相同,也可以相同.
两个对象的hashCode如果相同,只能说明它们在散列表数组中的位置相同,具体的比较还是要调用它们的 equals() 方法.
问题1:重写了equals()方法为什么还要重写hashCode()方法
如果重写 equals() 方法的这个类不用作 HashMap 的 key 使用,那么可以不重写 hashCode()方法.
如果需要作为HashMap的key使用,就必须重写.如果不重写,就会发生两个对象的 equals() 方法返回true, 但是它们的 hashCode() 值并不一样的情况,这就违反了Object 规范,直接导致的结果就是HashMap使用错误.
比如:
HashMap<Student, String> map = new HashMap<>();
map.put(new Student("aaa"), "10");
map.get(new Student("aaa"));
如果重写了 equals() 方法,那么第一个Student对象和第二个Student对象应该是相同的,但是结果返回的却是 null, 原因就是它们的 hashCode() 方法没有重写,导致散列值不同,所以返回 null.
问题2:两个对象的hashCode()相同,为什么HashMap还是能取出正确的值.
@Test
public void test6(){
System.out.println("ABCDEa123abc".hashCode()); // 165374702
System.out.println("ABCDFB123abc".hashCode()); // 165374702
Map<String,String> map = new HashMap<String,String>();
map.put("ABCDEa123abc","123");
map.put("ABCDFB123abc","321");
System.out.println(map.get("ABCDEa123abc"));
System.out.println(map.get("ABCDFB123abc"));
}
结果:
165374702
165374702
123
321
两个对象的hashCode相同,只能说明它们所处散列表数组的下标相同,具体的还要看它们本身是否相同,也就是 equals() 方法返回的是 true, 还是 false.
HashMap的 get(Object key)源码如下:
final Node<K,V> getNode(int hash, Object key) {
Node<K,V>[] tab; Node<K,V> 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<K,V>)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;
}
从第5行和第6行能够看到,如果hashCode相同,就会调用它们的equals() 方法.