重写equals和hashcode方法来使两个对象相等

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

环境

java:1.7

场景

最近在重构消息系统,客户端发送的订阅消息,在后台转成一个Message类,
假设客户端发送了两个一模一样的消息时,其生成的Message类也应该相等的;
这时就需要重写equalshashcode方法。

代码

Message类:

public class Message{
	private String apiUrl;
	private String params;
	private String type;
	
	public String getApiUrl() {
		return apiUrl;
	}
	public void setApiUrl(String apiUrl) {
		this.apiUrl = apiUrl;
	}
	public String getParams() {
		return params;
	}
	public void setParams(String params) {
		this.params = params;
	}
	public String getType() {
		return type;
	}
	public void setType(String type) {
		this.type = type;
	}
	@Override
	public String toString() {
		return "apiUrl=" + apiUrl + ", params=" + params + ", type=" + type;
	}
}

重写equals方法

@Override
public boolean equals(Object obj) {
	
	if(this == obj){
		return true;
	}else if(!(obj instanceof Message)){
		return false;
	}
	Message mo = (Message)obj;
	
	return this.toString().equals(mo.toString());
}

重写hashCode方法

使用缓存的方式:
Message再增加一个属性:

	private volatile int hascode = 0;
@Override
public int hashCode() {
	int result = hascode;
	if(result == 0){
		result = 17;
		result = result*31 + apiUrl.hashCode();
		result = result*31 + params.hashCode();
		result = result*31 + type.hashCode();
		hascode = result;
	}
	return result;
}

不使用缓存的方式:

@Override
public int hashCode() {
	int result = = 17;
	result = result*31 + apiUrl.hashCode();
	result = result*31 + params.hashCode();
	result = result*31 + type.hashCode();
	return result;
}

至此就已经完成了;

思考几个问题:

1、为什么要重写上面两个方法呢?
2、为什么一定要使用31这个数字来作为系数相乘呢?

问题1的理由

重写这两个方法的场景基本就是该对象要保存到HashMap这样的集合中去。
比如我的业务场景就要要保存到ConcurrentHashMap<Message, Long>集合中。
假设不重写的话,两个属性值都相同的Messagehashcode是不相同的,
因为对象的hashcode是根据内存的地址算出来的。

所以我们必须重写hashcode方法;
重写hashcode后,就需要重写equals方法,因为假设不重写的话,
默认的equals方法相等于== 即:判断两个引用是否指向内在中的同一个对象

所以也要重写。

问题2的理由

这个没有具体的答案:
老外给出的解释:

1、研究员发现素数31,可以更有效的分配key

2、之所以选择31,是因为它是个奇素数,如果乘数是偶数,并且乘法溢出的话,信息就会丢失,因为与2相乘等价于移位运算。使用素数的好处并不是很明显,但是习惯上都使用素数来计算散列结果。31有个很好的特性,就是用移位和减法来代替乘法,可以得到更好的性能:31*i==(i<<5)-i。现在的VM可以自动完成这种优化。

Well, when you stick your keys in the containers, depending on the prime used, you would get a different key number and therefore a different distribution of the keys in your array.


So the same key “abc” would be a31+b31+c31 for prime 31 and it would generate a different key for the abc with 29 – a29+b29+c29.

Since the key produced is different, the data would go into a different location depending on the prime used.


Researchers found that using a prime of 31 gives a better distribution to the keys, and lesser no of collisions. No one knows why, the last i know and i had this question answered by Chris Torek himself, who is generally credited with coming up with 31 hash, on the C++ or C mailing list a while back.

具体参考:https://computinglife.wordpress.com/2008/11/20/why-do-hash-functions-use-prime-numbers/

参考地址:

如何重写hashCode()和equals()方法

深入解析Java对象的hashCode和hashCode在HashMap的底层数据结构的应用

猜你喜欢

转载自blog.csdn.net/u013066244/article/details/83757908