最近在
复习的时候,又重新的
理解了下equals()和
hashCode().
equals()用于判断两个对象是否相等,这是大家公认的。
hashCode()被设计是用来使得哈希容器能高效的工作。
为什么这么说?在java中,有一些哈希容器,比如Hashtable,HashMap等等。当我们调用这些类的诸如get(Object obj)方法时,容器的内部肯定需要判断一下当前对象obj在容器中是否存在,以便进行后续的操作。判断是够存在,肯定是要比较两个对象是否相等,我们"应该"要使用equals()才是正确的。
但是如果哈希容器中的元素有很多的时候,使用equals()必然会很慢。这个时候我们想到一种替代方案就是hashCode()。hashCode()返回一个int类型,比较起来要快很多。但这也造成了一个问题,
就是一个判定两个对象事实上存在两个标准?当然不是这样的,正如在文章开头所说,hashCode()被设计用来使得哈希容器中能高效的工作。也只有在哈希容器中,才使用hashCode()来进行比较对象是否相等,而且还是弱的比较。
当我们调用哈希容器的get(Object obj)方法时,他会首先查看当前容器中是够存在相同的哈希值,如果不存在,那么返回null。如果存在,再调用当前对象的equals()方法比较一下看哈希处的对象是否和要查找的对象为相同的对象,如果不是,那么返回null。如果是,说明当前哈希容器存在相应的值,返回该哈希处的对象。
这样hashCode()方法就提高了哈希容器的效率,这就是hashCode()存在的
意义。我们可以把hashCode()相等看成是两个对象相等的必要非充分条件,equals()相等才是充分条件。
因此,在自定义一个类的时候,我们必须要同时重写equals()和hashCode(),并且必须保证:
1 如果两个对象的equals()相等,那么他们的hashCode()必定相等。
2 如果两个对象的hashCode()不相等,那么他们的hashCode()必定不等。
class="java">import java.util.HashMap;
public class Demo {
public static void main(String[] args) throws Exception{
Person person=new Person("xyz",22);
HashMap<Person,Integer> hashMap=new HashMap<Person,Integer>();
hashMap.put(person, 1);
System.out.println(hashMap.get(new Person("xyz",22)));
}
}
class Person{
private String name;
private int age;
public Person(String name,int age){
this.name=name;
this.age=age;
}
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;
}
@Override
public boolean equals(Object obj) {
// TODO Auto-generated method stub
if(this==obj)
return true;
if(obj instanceof Person){
Person person=(Person) obj;
if(this.age==person.getAge() && this.name.equals(person.getName()) )
return true;
}
return false;
}
// @Override
// public int hashCode() {
// return this.name.hashCode()*10+this.age;
// }
}
上面的代码
注释掉hashCode()前后的运行结果不同,当注释掉hashCode()的时候,person和后来新建的Person虽然equals是同一对象,但HashMap容器内部比较hashCode()的时候会认为他们是不同元素。
因此,牢记一点,当我们重写equals()方法时候一定要重写hashCode()方法。
下面我们来看看String类的equals方法和hashCode方法:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String) anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
public int hashCode() {
int h = hash;//默认是0
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;//String的哈希值由组成该String的字符串的ASCII值根据相应的规则加和
}