我们如何决定集合的hashCode()方法的最佳实现(假设equals方法已被正确重写)?
当前回答
如果我正确理解你的问题,你有一个自定义的集合类(即一个从集合接口扩展的新类),你想实现hashCode()方法。
如果您的集合类扩展了AbstractList,那么您就不必担心它,因为已经有equals()和hashCode()的实现,它通过遍历所有对象并将它们的hashCodes()相加来工作。
public int hashCode() {
int hashCode = 1;
Iterator i = iterator();
while (i.hasNext()) {
Object obj = i.next();
hashCode = 31*hashCode + (obj==null ? 0 : obj.hashCode());
}
return hashCode;
}
现在,如果你想要的是计算特定类哈希码的最佳方法,我通常使用^(按位排他或)操作符来处理我在equals方法中使用的所有字段:
public int hashCode(){
return intMember ^ (stringField != null ? stringField.hashCode() : 0);
}
其他回答
使用Apache Commons EqualsBuilder和HashCodeBuilder上的反射方法。
只是一个快速的注释,以完成其他更详细的答案(在代码方面):
如果我考虑如何在java中创建哈希表的问题,特别是jGuru FAQ条目,我相信可以判断哈希代码的其他标准是:
同步(算法是否支持并发访问)? 失败安全迭代(算法是否检测到迭代过程中发生变化的集合) 空值(哈希码是否支持集合中的空值)
首先确保equals被正确实现。摘自一篇IBM DeveloperWorks文章:
对称性:对于两个参考,a和b,当且仅当b等于(a)时,a等于(b) 自反性:对于所有非空引用,a.equals(a) 及物性:如果a等于(b) b等于(c),那么a等于(c)
然后确保它们与hashCode的关系尊重联系人(来自同一篇文章):
与hashCode()的一致性:两个相等的对象必须具有相同的hashCode()值
最后,一个好的哈希函数应该努力接近理想的哈希函数。
最好的实现?这是一个很难回答的问题,因为这取决于使用模式。
Josh Bloch的Effective Java在第8项(第二版)中提出了几乎所有情况下合理的良好实现。最好的办法是去查一下,因为作者在那里解释了为什么这种方法是好的。
简短的版本
Create a int result and assign a non-zero value. For every field f tested in the equals() method, calculate a hash code c by: If the field f is a boolean: calculate (f ? 0 : 1); If the field f is a byte, char, short or int: calculate (int)f; If the field f is a long: calculate (int)(f ^ (f >>> 32)); If the field f is a float: calculate Float.floatToIntBits(f); If the field f is a double: calculate Double.doubleToLongBits(f) and handle the return value like every long value; If the field f is an object: Use the result of the hashCode() method or 0 if f == null; If the field f is an array: see every field as separate element and calculate the hash value in a recursive fashion and combine the values as described next. Combine the hash value c with result: result = 37 * result + c Return result
这将导致在大多数使用情况下哈希值的适当分布。
最好使用Eclipse提供的功能,它做得非常好,您可以把精力和精力放在开发业务逻辑上。
推荐文章
- 在流中使用Java 8 foreach循环移动到下一项
- 访问限制:'Application'类型不是API(必需库rt.jar的限制)
- 用Java计算两个日期之间的天数
- 如何配置slf4j-simple
- 在Jar文件中运行类
- 带参数的可运行?
- 我如何得到一个字符串的前n个字符而不检查大小或出界?
- 我可以在Java中设置enum起始值吗?
- Java中的回调函数
- c#和Java中的泛型有什么不同?和模板在c++ ?
- 在Java中,流相对于循环的优势是什么?
- Jersey在未找到InjectionManagerFactory时停止工作
- 在Java流是peek真的只是调试?
- Recyclerview不调用onCreateViewHolder
- 将JSON字符串转换为HashMap