Eclipse source menu has a "generate hashCode / equals method" which generates functions like the one below.
Eclipse源菜单有一个“生成hashCode / equals方法”,它生成如下所示的函数。
String name;
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
CompanyRole other = (CompanyRole) obj;
if (name == null)
{
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
If I select multiple fields when generating hashCode()
and equals()
Eclipse uses the same pattern shown above.
如果我在生成hashCode()和equals()时选择多个字段,则Eclipse使用上面显示的相同模式。
I am not an expert on hash functions and I would like to know how "good" the generated hash function is? What are situations where it will break down and cause too many collisions?
我不是哈希函数的专家,我想知道生成的哈希函数是多么“好”?在什么情况下它会崩溃并导致太多碰撞?
16
You can see the implementation of hashCode function in java.util.ArrayList
as
您可以在java.util.ArrayList中看到hashCode函数的实现
public int hashCode() {
int hashCode = 1;
Iterator i = iterator();
while (i.hasNext()) {
E obj = i.next();
hashCode = 31*hashCode + (obj==null ? 0 : obj.hashCode());
}
return hashCode;
}
It is one such example and your Eclipse generated code follows a similar way of implementing it. But if you feel that you have to implement your hashCode by your own, there are some good guidelines given by Joshua Bloch in his famous book Effective Java. I will post those important points from Item 9 of that book. Those are,
这是一个这样的例子,您的Eclipse生成的代码遵循类似的实现方式。但是如果你觉得你必须自己实现你的hashCode,那么Joshua Bloch在他的着名书籍Effective Java中给出了一些很好的指导。我将从该书的第9项中发布那些重要的观点。那些是,
- Store some constant nonzero value, say, 17, in an int variable called result.
在一个名为result的int变量中存储一些常量非零值,比如17。
For each significant field f in your object (each field taken into account by the equals method, that is), do the following:
对于对象中的每个重要字段f(通过equals方法考虑的每个字段,即),执行以下操作:
a. Compute an int hash code c for the field:
一个。计算字段的int哈希码c:
i. If the field is a boolean, compute (f ? 1 : 0).
一世。如果该字段是布尔值,则计算(f?1:0)。
ii. If the field is a byte, char, short, or int, compute (int) f.
II。如果字段是byte,char,short或int,则为compute(int)f。
iii. If the field is a long, compute (int) (f ^ (f >>> 32)).
III。如果字段是long,则计算(int)(f ^(f >>> 32))。
iv. If the field is a float, compute Float.floatToIntBits(f).
IV。如果该字段是浮点数,则计算Float.floatToIntBits(f)。
v. If the field is a double, compute Double.doubleToLongBits(f), and then hash the resulting long as in step 2.a.iii.
v。如果该字段是double,则计算Double.doubleToLongBits(f),然后在步骤2.a.iii中对生成的long进行哈希处理。
vi. If the field is an object reference and this class’s equals method compares the field by recursively invoking equals, recursively invoke hashCode on the field. If a more complex comparison is required, compute a “canonical representation” for this field and invoke hashCode on the canonical representation. If the value of the field is null, return 0 (or some other constant, but 0 is traditional)
六。如果该字段是一个对象引用,并且该类的equals方法通过递归调用equals来比较该字段,则在该字段上递归调用hashCode。如果需要更复杂的比较,请为此字段计算“规范表示”,并在规范表示上调用hashCode。如果该字段的值为null,则返回0(或其他一些常量,但传统为0)
vii. If the field is an array, treat it as if each element were a separate field. That is, compute a hash code for each significant element by applying these rules recursively, and combine these values per step 2.b. If every element in an array field is significant, you can use one of the Arrays.hashCode methods added in release 1.5.
七。如果该字段是数组,则将其视为每个元素都是单独的字段。也就是说,通过递归地应用这些规则来计算每个重要元素的哈希码,并且每步骤2.b组合这些值。如果数组字段中的每个元素都很重要,则可以使用版本1.5中添加的Arrays.hashCode方法之一。
b. Combine the hash code c computed in step 2.a into result as follows:
湾将步骤2.a中计算的哈希码c组合到结果中,如下所示:
result = 31 * result + c;
Return result.
When you are finished writing the hashCode method, ask yourself whether equal instances have equal hash codes. Write unit tests to verify your intuition! If equal instances have unequal hash codes, figure out why and fix the problem.
编写完hashCode方法后,请问自己,相等的实例是否具有相同的哈希码。编写单元测试来验证你的直觉!如果相等的实例具有不相等的哈希码,请弄清楚原因并解决问题。
Java language designers and Eclipse seem to follow similar guidelines I suppose. Happy coding. Cheers.
我认为Java语言设计者和Eclipse似乎遵循类似的指导原则。快乐的编码。干杯。
10
Since Java 7 you can use java.util.Objects
to write short and elegant methods:
从Java 7开始,您可以使用java.util.Objects编写简短而优雅的方法:
class Foo {
private String name;
private String id;
@Override
public int hashCode() {
return Objects.hash(name,id);
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Foo) {
Foo right = (Foo) obj;
return Objects.equals(name,right.name) && Objects.equals(id,right.id);
}
return false;
}
}
5
Generally it is good, but:
一般来说它很好,但是:
番石榴做得更好,我更喜欢它。 [编辑:似乎从JDK7开始Java提供了类似的哈希函数]。
一些框架在直接访问字段时可能会导致问题,而不是像使用Hibernate那样使用setter / getter。对于Hibernate创建惰性的一些字段,它创建代理而不是真实对象。只有调用getter才能使Hibernate在数据库中获得真正的价值。
4
Yes, it is perfect :) You will see this approach almost everywhere in the Java source code.
是的,它是完美的:)您将在Java源代码中几乎无处不在地看到这种方法。
0
It's a standard way of writing hash functions. However, you can improve/simplify it if you have some knowledge about the fields. E.g. you can ommit the null check, if your class guarantees that the field never be null (applies to equals() as well). Or you can of delegate the field's hash code if only one field is used.
这是编写哈希函数的标准方法。但是,如果您对字段有一些了解,则可以改进/简化它。例如。如果你的类保证字段永远不为null(也适用于equals()),你可以省略null检查。或者,如果只使用一个字段,则可以委派字段的哈希码。
0
I would also like to add a reference to Item 9, in Effective Java 2nd Edition by Joshua Bloch.
我还想在Joshua Bloch的Effective Java 2nd Edition中添加对Item 9的引用。
Here is a recipe from Item 9 : ALWAYS OVERRIDE HASHCODE WHEN YOU OVERRIDE EQUALS
这是第9项的配方:当你超越平等时总是覆盖哈希码
- Store some constant nonzero value, say, 17, in an int variable called result.
在一个名为result的int变量中存储一些常量非零值,比如17。
- For each significant field f in your object (each field taken into account by the equals method, that is), do the following:
对于对象中的每个重要字段f(通过equals方法考虑的每个字段,即),执行以下操作:
a. Compute an int hash code c for the field:
i. If the field is a boolean, compute (f ? 1 : 0).
ii. If the field is a byte, char, short, or int, compute (int) f.
iii. If the field is a long,compute(int)(f^(f>>>32)).
iv. If the field is a float, compute Float.floatToIntBits(f).
v. If the field is a double, compute Double.doubleToLongBits(f), and then hash the resulting long as in step 2.a.iii.
vi. If the field is an object reference and this class’s equals method compares the field by recursively invoking equals, recursively invoke hashCode on the field. If a more complex comparison is required, compute a “canonical representation” for this field and invoke hashCode on the canonical representation. If the value of the field is null, return 0 (or some other constant, but 0 is traditional).
vii. If the field is an array, treat it as if each element were a separate field. That is, compute a hash code for each significant element by applying these rules recursively, and combine these values per step 2.b. If every element in an array field is significant, you can use one of the Arrays.hashCode methods added in release 1.5.
b. Combine the hash code c computed in step 2.a into result as follows: result = 31 * result + c; 3. Return result. 4. When you are finished writing the hashCode method, ask yourself whether equal instances have equal hash codes. Write unit tests to verify your intuition! If equal instances have unequal hash codes, figure out why and fix the problem.
0
If you are using Apache Software Foundation (commons-lang library) then below classes will help you to generate hashcode/equals/toString methods using reflection.
如果您使用的是Apache Software Foundation(commons-lang库),那么下面的类将帮助您使用反射生成hashcode / equals / toString方法。
You don't need to worry about regenerating hashcode/equals/toString methods when you add/remove instance variables.
添加/删除实例变量时,无需担心重新生成hashcode / equals / toString方法。
EqualsBuilder - This class provides methods to build a good equals method for any class. It follows rules laid out in Effective Java , by Joshua Bloch. In particular the rule for comparing doubles, floats, and arrays can be tricky. Also, making sure that equals() and hashCode() are consistent can be difficult.
EqualsBuilder - 这个类提供了为任何类构建一个好的equals方法的方法。它遵循Joshua Bloch撰写的Effective Java中规定的规则。特别是比较双精度数,浮点数和数组的规则可能很棘手。此外,确保equals()和hashCode()一致可能很困难。
HashCodeBuilder - This class enables a good hashCode method to be built for any class. It follows the rules laid out in the book Effective Java by Joshua Bloch. Writing a good hashCode method is actually quite difficult. This class aims to simplify the process.
HashCodeBuilder - 这个类可以为任何类构建一个好的hashCode方法。它遵循Joshua Bloch撰写的Effective Java一书中规定的规则。编写一个好的hashCode方法实际上非常困难。本课程旨在简化流程。
ReflectionToStringBuilder - This class uses reflection to determine the fields to append. Because these fields are usually private, the class uses AccessibleObject.setAccessible(java.lang.reflect.AccessibleObject[], boolean) to change the visibility of the fields. This will fail under a security manager, unless the appropriate permissions are set up correctly.
ReflectionToStringBuilder - 此类使用反射来确定要追加的字段。因为这些字段通常是私有的,所以该类使用AccessibleObject.setAccessible(java.lang.reflect.AccessibleObject [],boolean)来更改字段的可见性。除非正确设置了适当的权限,否则这将在安全管理器下失败。
Maven Dependency:
commons-lang
commons-lang
${commons.lang.version}
Sample Code:
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ReflectionToStringBuilder;
public class Test{
instance variables...
....
getter/setter methods...
....
@Override
public String toString() {
return ReflectionToStringBuilder.toString(this);
}
@Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);
}
@Override
public boolean equals(Object obj) {
return EqualsBuilder.reflectionEquals(this, obj);
}
}
0
One potential drawback is that all objects with null fields will have a hash code of 31, thus there could be many potential collisions between objects that only contain null fields. This would make for slower lookups in Maps
.
一个潜在的缺点是具有空字段的所有对象将具有31的散列码,因此在仅包含空字段的对象之间可能存在许多潜在的冲突。这会使地图中的查找速度变慢。
This can occur when you have a Map
whose key type has multiple subclasses. For example, if you had a HashMap