在Java 7中我们有
o.hashCode();
Objects.hashCode(o);
Objects.hash(o);
前两个与零点检查大致相同,但最后一个是什么?
提供单个对象引用时,返回的值为 不等于该对象引用的哈希码。
为什么?我的意思是,我们不需要3种做同样事情的方法,我理解这一点,但为什么我们需要Objects.hash()
呢?你什么时候选择使用一个与另一个?
答案 0 :(得分:71)
请参阅hashCode
和hash
的文档。 hash
需要Object...
而hashCode
需要Object
。给出的例子是:
@Override public int hashCode() {
return Objects.hash(x, y, z);
}
Objects.hash(Object... values)
。定义自己的hashCode
方法时,需要一个简单编码的哈希值来构成对象标识的多个值。Objects.hashCode(Object o)
,如果对象为空,则不应抛出。Object::hashCode()
,如果对象为空,则会抛出异常。请注意,hash(o)
和hashCode(o)
不一定会返回相同的内容!如果您是针对单个对象执行此操作,则应该使用hashCode
。
答案 1 :(得分:11)
Object的默认hashCode()返回对象的内存地址。所以如果你有以下课程:
class Car {
String make;
String model;
int year;
public Car(String make, String model, int year) {
this.make = make;
this.model = model;
this.year = year;
}
}
然后创建两个对象:
Car car1 = new Car("Toyota", "Corolla", 2010);
Car car2 = new Car("Toyota", "Corolla", 2010);
car1.hashCode()与car2.hashCode()不同,因为每个对象都有不同的内存地址。
如果你想让car1和car2都返回相同的哈希码怎么办?在这种情况下,您应该覆盖Car类的默认Object hashCode()方法,如下所示:
@Override
public int hashCode() {
Object[] x = {model, make, Integer.valueOf(year)};
int hashArray = Arrays.hashCode(x);
return hashArray;
}
这将使car1.hashCode()等于car2.hashCode(),因为String.hashCode()根据字符串内容计算hashCode,而Integer.hashCode()将返回整数值本身。
在Java 7中,您可以使用Objects.hash(Object ... values)。所以我们的新Car hashCode()看起来如下:
@Override
public int hashCode() {
return Objects.hash(model, make, year);
}
Objects.hash(Object ... values)将为您调用Arrays.hashCode。
最后,Objects.hashCode(Object o)将进行空检查。如果对象为null,它将返回0。否则,它将调用对象hashCode()方法。
答案 2 :(得分:11)
Objects.hashCode
实用程序方法Objects.hashCode( Object o )
仅对传递的对象调用hashCode
方法。
那为什么要发明或使用这种方法呢?为什么不自己调用对象的hashCode
方法呢?
此方法提供了一个好处:NULL
➙0
。实用程序方法容忍null。
Objects.hashCode( myObject )
为myObject
的{{1}},则会得到零(0)。 NULL
为myObject.hashCode()
时调用myObject
会引发NULL
参数。 是否需要容忍null取决于您在特定情况下的判断。
NullPointerException
实用程序方法Objects.hash( Object o , … )
具有不同的用途。此方法分为两个阶段:
Objects.hash
,收集每个结果。如果传递单个对象.hashCode
,则首先调用并收集Objects.hash( myObject )
,然后计算该单项集合的哈希值。因此,您最终得到了hash的哈希值。
散列单个对象时,至关重要的是要了解myObject.hashCode
返回的结果与Objects.hashCode( myObject )
不同。实际上,第二个返回第一个结果的哈希值。
在这两个Objects.hash( myObject )
方法中采用的方法逻辑本身就很有意义。
不幸的是,实际上,对于那些试图在我们的POJO上编写代码以覆盖Objects
并相应地hashCode
编写代码的日常使用中,我们必须三思而后行。决定给谁打电话。
equals
(和hashCode
)替代基于您的班级中的单个成员,请使用equals
。 Objects.hashCode( member )
(和hashCode
)替代基于您课程的多个属性,请使用equals
。 Objects.hash( memberA , memberB , memberC )
@Override
public int hashCode() {
return this.member.hashCode() ; // Throws NullPointerException if member variable is null.
}
@Override
public int hashCode() {
return Objects.hashCode( this.member ) ; // Returns zero (0) if `this.member` is NULL, rather than throwing exception.
}
我们可以很简单地测试这些各种方法。
我们以一个UUID
对象为例。 UUID(通用唯一标识符)是一个128位的值,其中某些位具有某些语义。
@Override
public int hashCode() {
return Objects.hash( this.memberA , this.memberB , this.memberC ) ; // Hashes the result of all the passed objects’ individual hash codes.
}
的 OpenJDK 实现在内部将128位值表示为一对64位UUID
整数。
该实现重写了long
和Object::equals
来查看存储在该对长整数中的数据。这是source code for those two methods。
Object::hashCode
public boolean equals(Object obj) {
if ((null == obj) || (obj.getClass() != UUID.class))
return false;
UUID id = (UUID)obj;
return (mostSigBits == id.mostSigBits &&
leastSigBits == id.leastSigBits);
}
实例化我们的UUID对象。
public int hashCode() {
long hilo = mostSigBits ^ leastSigBits;
return ((int)(hilo >> 32)) ^ (int) hilo;
}
计算我们的哈希值。
UUID uuid = UUID.randomUUID();
转储到控制台。
int hash1 = uuid.hashCode();
int hash2 = Objects.hashCode( uuid ); // Result matches line above.
int hash3 = Objects.hash( uuid ); // Returns a hash of a hash.
int hash4 = Objects.hash( uuid.hashCode() ); // Result matches line above.
请参阅此code run live at IdeOne.com。
uuid.toString():401d88ff-c75d-4607-bb89-1f7a2c6963e1
1/2 = 278966883 | 278966883
3/4 = 278966914 | 278966914