环境
java:1.7
场景
最近在重构消息系统,客户端发送的订阅消息,在后台转成一个Message
类,
假设客户端发送了两个一模一样的消息时,其生成的Message
类也应该相等的;
这时就需要重写equals
和hashcode
方法。
代码
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>
集合中。
假设不重写的话,两个属性值都相同的Message
的hashcode
是不相同的,
因为对象的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/
参考地址: