解析Java对象的equals()和hashCode()的使用

来源:互联网 发布:网络公司员工合同 编辑:程序博客网 时间:2024/06/03 12:28

 

 

在Java语言中,equals()和hashCode()两个函数的使用是紧密配合的,你要是自己设计其中一个,就要设计另外一个。在多数情况下,这两个函数是不用考虑的,直接使用它们的默认设计就可以了。但是在一些情况下,这两个函数最好是自己设计,才能确保整个程序的正常运行。最常见的是当一个对象被加入收集对象(collection object)时,这两个函数必须自己设计。更细化的定义是:如果你想将一个对象A放入另一个收集对象B里,或者使用这个对象A为查找一个元对象在收集对象B里位置的钥匙,并支持是否容纳,删除收集对象B里的元对象这样的操作,那么,equals()和hashCode()函数必须开发者自己定义。其他情况下,这两个函数是不需要定义的。

 

1 equals():

它是用于进行两个对象的比较的,是对象内容的比较,当然也能用于进行对象地址的比较。
这种比较是默认的对象比较方式,在Object这个对象中,这种方式就已经设计好了。

看看equals()方法在Object类中的定义:

public boolean equals(Object obj){
    
return (this == obj);
}

明显是比较指针(地址)

但是为什么会有equals是比较内容的这种说法呢?

因为在String、Double等封装类中,已经重载(overriding)了Object类的equals()方法,于是有了另一种计算公式,是进行内容的比较。


对象内容的比较才是设计equals()的真正目的,Java语言对equals()的要求如下,这些要求是必须遵循的。否则,你就不该浪费时间:

    * 对称性:如果x.equals(y)返回是“true”,那么y.equals(x)也应该返回是“true”。
    * 反射性:x.equals(x)必须返回是“true”。
    * 类推性:如果x.equals(y)返回是“true”,而且y.equals(z)返回是“true”,那么z.equals(x)也应该返回是“true”。
    * 还有一致性:如果x.equals(y)返回是“true”,只要x和y内容一直不变,不管你重复x.equals(y)多少次,返回都是“true”。
    * 任何情况下,x.equals(null),永远返回是“false”;x.equals(和x不同类型的对象)永远返回是“false”。

java-equals()覆盖模板


2 hashCode():
这个函数返回的就是一个用来进行赫希操作的整型代号。hashCode()所返回的值是用来分类对象在一些特定的收集对象中的位置。这些对象是HashMap, Hashtable, HashSet,等等。这个函数和上面的equals()函数必须自己设计,用来协助HashMap, Hashtable, HashSet,等等对自己所收集的大量对象进行搜寻和定位。

 

比如在String类中:

public int hashCode() { 
    
int h = hash; 
    
if (h == 0) { 
        
char val[] = value; 
        
int len = count; 
        
for (int i = 0; i < len; i++) { 
            h 
= 31*+ val[off++]; 
        } 
        hash 
= h; 
    } 
    
return h; 
}

 

这些收集对象究竟如何工作的,想象每个元对象hashCode是一个箱子的编码,按照编码,每个元对象就是根据hashCode()提供的代号归入相应的箱子里。所有的箱子加起来就是一个HashSet,HashMap,或 Hashtable对象,我们需要寻找一个元对象时,先看它的代码,就是hashCode()返回的整型值,这样我们找到它所在的箱子,然后在箱子里,每个元对象都拿出来一个个和我们要找的对象进行对比,如果两个对象的内容相等,我们的搜寻也就结束。这种操作需要两个重要的信息,一是对象的 hashCode(),还有一个是对象内容对比的结果。

hashCode()的返回值和equals()的关系如下:

    * 如果x.equals(y)返回“true”,那么x和y的hashCode()必须相等。
    * 如果x.equals(y)返回“false”,那么x和y的hashCode()有可能相等,也有可能不等。


为什么这两个规则是这样的,原因其实很简单,拿HashSet来说吧,HashSet可以拥有一个或更多的箱子,在同一个箱子中可以有一个或更多的独特元对象(HashSet所容纳的必须是独特的元对象)。这个例子说明一个元对象可以和其他不同的元对象拥有相同的hashCode。但是一个元对象只能和拥有同样内容的元对象相等。所以这两个规则必须成立。

 

3.两者的关系

①两个obj,如果equals()相等,hashCode()一定相等

②两个obj,如果hashCode()相等,equals()不一定相等

原因:从散列的角度考虑,不同的对象计算哈希码的时候,可能引起冲突,大家一定还记得数据结构中冲突的解决方案吧

 

但是要这么设计,用两个函数,个人的理解是为了比较两个对象时更高效。

可以考虑在Java集合中,判断两个对象是否相等的规则是:

第一步,如果hashCode()相等,则查看第二步,否则不相等;

第二步,查看equals()是否相等,如果相等,则两obj相等,否则还是不相等。

 

为什么这样做?个人的理解是让适当的函数完成适当的功能,毕竟hashCode()比equals()在某种程度上来得快。

原创粉丝点击