`
caizi0413
  • 浏览: 6842 次
  • 性别: Icon_minigender_1
  • 来自: 广州
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

我谈hashcode与equals

 
阅读更多
甚是悲哀,工作都已经两年半了,对hashcode和equals还是似懂非懂...
这两天决定找些资料来研究研究,如下即是个人理解,欠妥之处请批评指正。

1.在java里面,默认情况下所有的类都会继承Object类。所以,我们先开始了解Object类里面的
hashcode与equals方法。
public native int hashCode();//调用java里面的本地方产生哈希码
public boolean equals(Object obj) {//这里比较对象地址
return (this == obj);
}
public String toString() {//默认的toString方法与哈希码相关
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
2.下面代码证明Object类产生的哈希码不是内存地址
                ArrayList list = new ArrayList();
int numberExist = 0;
// 证明hashcode的值不是内存地址
for (int i = 0; i < 10000; i++) {
Object obj = new Object();
if (list.contains(obj.toString())) {//判断对象哈希码
System.out
.println(obj.toString() + "exists in the list. " + i);
numberExist++;
} else {
list.add(obj.toString());
}
}
System.out.println("repetition number:" + numberExist);
System.out.println("list size:" + list.size());
运行后,发现不同对象哈希码相同了,所以得出哈希码不是内存地址,否则哈希码是不会相同了。
3.下面代码证明Object类的equals方法比较的是内存地址
numberExist = 0;
list.clear();
for (int i = 0; i < 10000; i++) {
Object obj = new Object();
if (list.contains(obj)) {//对象判断,contains方法调用equal
System.out.println(obj + " exists in the list. " + i);
numberExist++;
} else {
list.add(obj);
}
}
System.out.println("repetition number:" + numberExist);
System.out.println("list size:" + list.size());

运行后得出结论,Object类的equals比较的对象的内存地址。

4.所以,从上面的例子看出,Object类的hashcode是这样一个机制。
举个例子来说,比如现有数据1 2 3 4 5 产生了不同的哈希码,现在又有数据6 7 8 9 10数据存储,假设hashcode根据某一机制产生与1 2 3 4 5一一对应的哈希码,那么现在,我们有理由相信,1和6的哈希码因为相同,2和7的哈希码相同...所以就有了一个桶的概念,即1和6同属于一个哈希链,这条链的哈希码是相同的;哈希码相同,那么怎么判断同一个桶里面的对象是否相等的?自然而然,那是equals的用处了。
简言之,hashcode是将对象按一定机制散列到内存归桶,而equals则在判断同一个桶里的对象是否相同。

5.那么哈希码是用来干什么的呢?用来提高查询效率的。比如有12345678910个数,如果现在要找10这个数字,那么常规数组的话,需要比较10次,而用哈希码即到对应的桶查找,有就比较,没有就返回就可以了。效率明显高了。

6.下面看个例子,自己可以通过注释掉hahscode equals方法试着运行

public class Test {

public static void main(String[] args) {
Map m = new HashMap();
m.put(new PhoneNumber(020, 12345678), "shellfeng");
System.out.println(m.get(new PhoneNumber(020, 12345678)));

}

private static class PhoneNumber {
private short areaCode;
private short extension;

public PhoneNumber(int areaCode, int extension) {
this.areaCode = (short) areaCode;
this.extension = (short) extension;
}

public boolean equals(Object o) {//在桶里查找对象,按自己设定规则
if (o == this) {
return true;
}
if (!(o instanceof PhoneNumber)) {
return false;
}
PhoneNumber pn = (PhoneNumber) o;
return pn.extension == extension && pn.areaCode == areaCode;//桶类型对象判断是否相同的规则
}
public int hashCode() {//将对象归类,即分属于不同的桶,如改为return 1则意味着所有对象放一号桶
int result = 17;
result = 37 * result + areaCode;
result = 37 * result + extension;
return result;
}
}
}
一般地说,hashcode和equals方法要么同时重写,要么同时覆盖。
如上例,重写任何一方都没多大意义。

7.有个规则:a.equals()=b.equals(),那么,a.hashcode()=b.hashcode()
            a.hashcode()!=b.hashcode(),那么,a.equals!=b.equals()

8.查看Integer源码发现,equals和hashcode都与Integer的值相关,即可以看出
只要是数值不相等的两个数,hashcode和equals都不一样,所以hashcode这个桶(哈希链)概念就没什么意思了。

9.一般数组与hashcode散列的效率

public class Test {

public static void main(String[] args) {
Integer[] datas = new Integer[2000000];
Map<Integer,Integer> map= new HashMap<Integer,Integer>();
for (int i = 0; i < datas.length; i++) {
datas[i] = i;
map.put(i, i);
}

long t1 = new Date().getTime();
for (int i = 0; i < datas.length; i++) {
if (datas[i] == 1888888) {
break;
}
}
//System.out.println("----------->"+ map.get(1888888));
long t2 = new Date().getTime() - t1;
System.out.println("----------->" + t2);
}

}










分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics