java--map容器的hashcode和equals

Posted on 2013-08-03 22:05  冰天雪域  阅读(1088)  评论(0编辑  收藏  举报

先看一个例子

首先定义一个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 的作用


 


 

 

Copyright © 2024 冰天雪域
Powered by .NET 9.0 on Kubernetes