您的位置:首页 > 其它

==和equals扩展-->重写equals()和hashcode()

2016-05-17 22:31 239 查看
上一篇博文提及了==和equals的比较,提到==比较的是引用,而equals比较的是具体引用的值。随着深入的了解,这只是通过代码比较浅地理解了这二者方法在实际应用中的用法,继续深入,不得不提及重写equals()和hashcode()。

首先,我们在初学的时候,听的比较多的说法是String类是重写了equals()和hashcode(),当然初学的时候只是当成了口诀一般牢记在心(八大基本数据类型也重写了equals()和hashcode())。随着深入的学习和应用,我们得理解为什么要重写这两个方法。

首先看一下java.lang包中Object类源码中的equals()和hashcode()。

equals:

public boolean equals(Object obj) {
return (this == obj);
}
我们可以看出,equals()在此时其实只是进行了==的比较(地址比较),而不是上篇博文中提到的比较对象的内容。

hashcode:

public native int hashCode();
而hashcode()更是没有进行任何的逻辑操作,用native修饰,调用了其实是hash算法。

然后在看看String中重写的equals()和hashcode()。

equals:

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;
}
1.其首先比较了引用的地址,如果相同,则为true;

2.若地址不同,则两个String对象中每个字符,这样就解释了equals的作用。

hashcode:

public int hashCode() {
int h = hash;
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;
}
同样的hashcode运用hash算法,保证了两个String对象有一样的hash码。

那么为什么在实际中要重写equals()和hashcode()。

下面看一个简单的例子。

package com.Test;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class Test {
public void main(String[] args) {
Set<Person> set = new HashSet<Person>();
set.add(new Person("Tom", "12"));
set.add(new Person("Jude", "11"));
set.add(new Person("Tom", "12"));
Iterator<Person> it = set.iterator();
while (it.hasNext()) {
System.out.println(it.next().toString());
}
}
class Person {
public String name;
public String age;
public Person(String name, String age) {
super();
this.name = name;
this.age = age;
}
@Override
public String toString() {
// TODO Auto-generated method stub
return name + "--" + age;
}

}
}


输出的结果是

Jude--11
Tom--12
Tom--12
如果这段代码起到的是一个录入人员信息的功能,而两个Tom其实是同一个人,只是录入的时候误操作录入两遍,那么这显然不是我们想要的结果。

这时候重写equals()和hashcode()排上用场了,改写Person类代码如下:

class Person {
public String name;
public String age;
public Person(String name, String age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
@Override
public String toString() {
// TODO Auto-generated method stub
return name + "--" + age;
}
@Override
public boolean equals(Object obj) {
// TODO Auto-generated method stub
if (obj instanceof Person) {
if (((Person) obj).getName() == this.name && ((Person) obj).getAge() == age) {
return true;
}
}
return false;
}
@Override
public int hashCode() {
// TODO Auto-generated method stub
return this.name.hashCode()+this.age.hashCode();
}
}


输出结果:

Jude--11
Tom--12
这样就是我们想要的结果了。

继续挖一会^ _^....

这时,如果Person类不重写hashcode(),而只重写equals(),按照原来的分析,这个时候在main函数添加上两行关于Tom的比较(其余代码不变)

System.out.println("Tom equals: "+(new Person("Tom", "12").equals(new Person("Tom", "12"))));
System.out.println("Tom ==: "+(new Person("Tom", "12").equals(new Person("Tom", "12"))));
得出结果

Tom equals: true
Tom ==: true
Tom--12
Tom--12
Jude--11
这显然违背了我们的初衷,既然Tom是同一个Tom,为什么在set中会有两个Tom呢?

而重写了hashcode()后,得出了我们想要的结果:

Tom equals: true
Tom ==: true
Jude--11 Tom--12
其实刚才重写了equals而没重写hashcode,在java中是不规范的,从上一例中就可以看出重写equals必须重写hashcode的必要了。

那么现在按照我自己的理解来解释下为什么重写equals必须重写hashcode,这个问题的我们就从上例中用到的HashSet来作为切入点展开。

java中集合类总的来说有List和Set,我们知道List是有序,元素可以重复,而Set元素无序,不可重复。那么Set如何保证其不可重复呢,就如上例中重写的equals那般,进行比较来判断,但是问题来了,如果只是3个对象,比较是很快的,但是如果此时Person类有成千上万个对象,那equals调用的次数就大大增加,此时的开销就很大了。而采用hash表来判断两个对象是否是同一个对象(使用hashcode来返回对象存储的物理地址),效率就大大增加了。这样我们往Set中添加新元素,通过hashcode把它的物理地址定位好,然后比较hashcode也是就比较物理地址,想想效率也是很高的。

现在可以总结下

1.equals为true,那么hashcode必须相同

2.equals为false,那么hashcode不一定相同(hashcode生成的时候,可能产生冲突,凑巧两个不同地址的hashcode一样,当然我觉得概率不大)

3.hashcode不同,equals必为false

以上只是自己的总结,有不对的地方希望大家能指正,帮我指出一个错误,对我来说都是一个进步。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: