结合HashMap对equals and hashcode详解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/about4years/article/details/70495499

这2个方法是在Object类中定义的,我们可以看下官方jdk对它们的定义(一部分):

If two objects are equal according to the {@code equals(Object)} method, then calling the {@code hashCode} method on each of the two objects must produce the same integer result.

It is not required that if two objects are unequal according to the{@link java.lang.Object#equals(java.lang.Object)}method, then calling the {@code hashCode} method on each of the two objects must produce distinct integer results.  However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hash tables.

第一段:如果2个对象equals为true,那么他们的hashcode必须返回同样的值。

第二段:如果2个对象equals为false,那么他们的hashcode也可以返回同样的值。

还有这句话:However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hash tables.

对于不equal的对象返回不同的hashcode值会提高"某些集合类"的性能(就是这些在放入对象到集合时需要判断对象是否相等的集合)

为什么呢?

扫描二维码关注公众号,回复: 5383614 查看本文章

想象一下,放入1000个对象到hashmap中,如果没有hashcode方法,那么就需要调用1000次equals方法,但是有了hashcode方法,我们可以先判断hashcode相不相等,不相等的话就直接可以判定这2个对象不相等,而这个的前提是建立在你对这个对象的这两个方法的定义:你确保了不相等的对象一定返回不同的hashcode;相等再去调用equals方法比较。(equals方法的性能开销是绝对大于hashcode的)

我们可以看下源码(比较的这一段):

if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))


可以看到如果hash值不一样,就不会去计算&& 后面的这个判定方法(即equals方法)

我们可以用代码去验证一下:

class Country {

	String name;
	long population;

	public Country(String name, long population) {
		this.name = name;
		this.population = population;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public long getPopulation() {
		return population;
	}

	public void setPopulation(long population) {
		this.population = population;
	}
	@Override
	public int hashCode() {
		if (this.name.length() % 2 == 0)
			return 390;
		else
			return 950;
	}

	@Override
	public boolean equals(Object obj) {
		return true;
	}

}

public class HashMapStructure {

	public static void main(String[] args) {

		Country india = new Country("india", 1000);
		Country japan = new Country("japan", 10000);
		System.out.println(india.hashCode());
		Country france = new Country("france", 2000);
		Country russia = new Country("russia", 20000);
		System.out.println(france.hashCode());
		HashMap<Country, String> countryCapitalMap = new HashMap<Country, String>();
		countryCapitalMap.put(russia, "Moscow");
		countryCapitalMap.put(india, "Delhi");
		countryCapitalMap.put(japan, "Tokyo");
		countryCapitalMap.put(france, "Paris");
		
		System.out.println(countryCapitalMap.size());
		Iterator<Country> countryCapitalIter = countryCapitalMap.keySet().iterator();
		while (countryCapitalIter.hasNext()) {
			Country countryObj = countryCapitalIter.next();
			String capital = countryCapitalMap.get(countryObj);
			System.out.println(countryObj.getName() + "----" + capital);
		}
	}

}


定义了一个country类,name和population2个属性,定义了一个hashmap存放country以及其首都名字。

注意country类的equals和hashcode方法,如果country名字是单数返回同样的hashcode,双数返回另一个hashcode,而equals我直接返回true,这意味着所有country对象调用这个函数都比较true;

这意味着当这样前后放入:

countryCapitalMap.put(india, "Delhi");
countryCapitalMap.put(japan, "Tokyo");

第一个(india)hash到对应地址,填入,第二个(japan)hash到对应地址,显然japan hash计算后返回与india相同的值,产生冲突,所以接下来要判断key是否相等(如果相等,覆盖value,不相等,则就是所谓的哈希冲突,java的解决办法是链地址法,即用一个链表将hash值相等的对象串起来。所以hash函数最后设计的尽量分布,避免产生冲突),显然hashcode相等,再比较equals,当然也是返回true,所以此时覆盖value,india的首都就变成了tokoy。

这里其实也可以看出来,如果2个对象equals返回true,但是hashcode不相等,那么这2个对象在计算hash地址时一定不会冲突,那么都可以添加到map中,但是其实2个对象是相等的,那么就违反了hashmap的规则。

所以最终程序输出:

2

russia----Paris

india----Tokyo

put方法就讲到这里。

to be continued..

猜你喜欢

转载自blog.csdn.net/about4years/article/details/70495499