您的位置:首页 > 编程语言 > Java开发

java--map容器的hashcode和equals

2013-08-02 21:59 309 查看
先看一个例子

首先定义一个user类。

package com.text.tool;

public class User {
int id;

User(int id) {
this.id = id;
}

public String toString() {
return "key="+id;
}
}


其次写一个测试类,创建一个HashMap,在map中User对象作为KEY。

package com.text.tool;

import java.util.HashMap;
import java.util.Map;

public class TestMap {

public static void main(String[] args) {
Map map = new HashMap();
map.put(new User(1), 1);
map.put(new User(2), 1);
map.put(new User(3), 1);

System.out.println(map.keySet());
System.out.println(map.get(new User(1))
}
}


输出结果,让人疑惑的是为什么MAP数组中匹配不到new User(1)。

[key=1, key=2, key=3]
null

我们可以简单看下HashMap源码,在源码中获取到key对应value做了一个判断,e.hash == hash && eq(k, e.key)也就是对key的hashcode进行比对,以及进行equals判断。

我们传入的对象User默认继承Object,所以equals及hashCode默认是Object的方法,而此时这里的equals比较的是两个对象的内存中的地址并非value,所以第二个new User(1)就无法再MAP数组中取到value了。

public Object get(Object key) {
Object k = maskNull(key);
int hash = hash(k);
int i = indexFor(hash, table.length);
Entry e = table[i];
while (true) {
if (e == null)
return e;
if (e.hash == hash && eq(k, e.key))
return e.value;
e = e.next;
}
}

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

public native int hashCode();


在User类中重写equals及hashcode方法,在启用main方法就不会有问题了。

package com.text.tool;

public class User {
int id;

User(int id) {
this.id = id;
}

public String toString() {
return "key="+id;
}

public int hashCode() {
return id;
}

public boolean equals(Object o) {
return o instanceof User && (id == ((User) o).id);
}
}

执行MAIN方法输出结果:

[key=2, key=1, key=3]
1


截取think in java一段描述:



equals()相等的两个对象,hashcode()一定相等;
equals()不相等的两个对象,却并不能证明他们的hashcode()不相等。换句话说,equals()方法不相等的两个对象,hashcode()有可能相等。(我的理解是由于哈希码在生成的时候产生冲突造成的)。
反过来:hashcode()不等,一定能推出equals()也不等;hashcode()相等,equals()可能相等,也可能不等。解释下第3点的使用范围,我的理解是在object、String等类中都能使用。在object类中,hashcode()方法是本地方法,返回的是对象的地址值,而object类中的equals()方法比较的也是两个对象的地址值,如果equals()相等,说明两个对象地址值也相等,当然hashcode()也就相等了;在String类中,equals()返回的是两个对象内容的比较,当两个对象内容相等时,
Hashcode()方法根据String类的重写代码的分析,也可知道hashcode()返回结果也会相等。以此类推,可以知道Integer、Double等封装类中经过重写的equals()和hashcode()方法也同样适合于这个原则。当然没有经过重写的类,在继承了object类的equals()和hashcode()方法后,也会遵守这个原则。

附下哈希表结构:



在一个数组中存储对象时,通过 hashCode 得到的哈希值来计算数组的索引位置(通常是求余运算),然后根据这个索引位置进行存取。多个对象计算出来的索引位置相同(叫hash冲突)时,用链表保存。冲突怎么保证取到的就是自己呢?那么就要用到 Object.equals() 方法。

所以要把对象存储在像 hash table类似的数据结构(比如:HashSet)中,hashCode 与 equals 要成对实现。

部分内容来源:

java中hashcode()和equals()的详解

hashcode 的作用
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: