Objects.hash()vs Objects.hashCode(),需要澄清

Jam*_*sev 53 hashcode java-7

好的,所以在Java 7中我们有

o.hashCode();
Objects.hashCode(o);

    Objects.hash(o);
Run Code Online (Sandbox Code Playgroud)

前两个与零点检查大致相同,但最后一个是什么?

提供单个对象引用时,返回的值不等于该对象引用的哈希代码.

这是为什么?我的意思是,我们不需要3种做同样事情的方法,我理解......但为什么我们需要Objects.hash()呢?你什么时候选择使用一个与另一个?

Tim*_* S. 74

请参阅文件hashCodehash. hash需要Object...一段hashCode时间Object.给出的例子是:

@Override public int hashCode() {
    return Objects.hash(x, y, z);
}
Run Code Online (Sandbox Code Playgroud)
  • Objects.hash(Object... values)当你想要一个对象序列的哈希时,例如在定义你自己的hashCode方法时,需要一个简单编码的哈希值来构成你的对象的身份.
  • Objects.hashCode(Object o) 当你想要单个对象的散列时,应该使用它,如果对象为null则不抛出.
  • Object::hashCode() 当你想要单个对象的散列时应该使用,如果对象为null则抛出异常.

请注意,hash(o)hashCode(o)不一定返回同样的事情!如果您是为单个对象执行此操作,则应该使用hashCode.

  • @CraigOtis`Objects.hash`只是调用`Arrays.hashCode`(http://hg.openjdk.java.net/jdk10/jdk10/jdk/file/777356696811/src/java.base/share/classes/java/util /Objects.java#l145)和单个对象的“ hashCode”与其中包含单个对象的数组的“ hashCode”不同(http://hg.openjdk.java.net/jdk10/jdk10/jdk /file/777356696811/src/java.base/share/classes/java/util/Arrays.java#l4677) (5认同)
  • 在什么情况下 `hash(o)` 和 `hashCode(o)` 不会返回相同的值?`hash()` 的文档指出`警告:当提供单个对象引用时,返回的值不等于该对象引用的哈希码。`,但我仍在挖掘原因。 (2认同)

Bas*_*que 18

Objects.hashCode

实用程序方法Objects.hashCode( Object o )只是hashCode在传递的对象上调用该方法。

容忍NULL

那么为什么要发明或使用这种方法呢?为什么不hashCode自己调用对象的方法呢?

这种方法提供了一个好处:NULL0。实用程序方法容忍null。

  • 如果调用Objects.hashCode( myObject )where myObjectNULL,则返回零(0)。
  • 相反,调用myObject.hashCode()when myObjectNULL会引发NullPointerException参数。

是否需要容忍null取决于您在特定情况下的判断。

Objects.hash

实用方法Objects.hash( Object o , … )具有不同的目的。此方法分为两个阶段:

  • 调用.hashCode每个传递的对象,收集每个结果。
  • 计算收集到的结果的哈希值。

哈希值

如果传递单个对象,则Objects.hash( myObject )首先myObject.hashCode调用并收集,然后计算该单个项目集合的哈希值。因此,您最终得到的是哈希值。

散列单个对象时,务必要了解与Objects.hashCode( myObject )返回不同的结果Objects.hash( myObject )。实际上,第二个返回第一个结果的哈希值。

在实践中烦人

就这两种Objects方法本身而言,采用这两种方法的逻辑是有意义的。

不幸的是,在实践中,对于我们这些试图对我们的POJO编写代码时要覆盖使用他们在每天的日常使用hashCode,并相应地equals,我们必须三思而后行,以决定哪些打电话。

  • 如果您的hashCode(和equals)替代基于类的单个成员,请使用Objects.hashCode( member )
  • 如果您的hashCode(和equals)替代基于您类的多个属性,请使用Objects.hash( memberA , memberB , memberC )

单成员,不容忍NULL

@Override
public int hashCode() {
    return this.member.hashCode() ;  // Throws NullPointerException if member variable is null.
}
Run Code Online (Sandbox Code Playgroud)

单成员,容忍NULL

@Override
public int hashCode() {
    return Objects.hashCode( this.member ) ;  // Returns zero (0) if `this.member` is NULL, rather than throwing exception.
}
Run Code Online (Sandbox Code Playgroud)

多成员,容忍NULL

@Override
public int hashCode() {
    return Objects.hash( this.memberA , this.memberB , this.memberC  ) ;  // Hashes the result of all the passed objects’ individual hash codes.  
}
Run Code Online (Sandbox Code Playgroud)

我们可以非常简单地测试这些各种方法。

UUID

让我们以一个UUID对象为例。甲UUID通用唯一标识符)是一个128位的值,其中的某些比特具有一定的语义。

所述的OpenJDK执行UUID内部表示128位的值作为一对64位的long整数。

相同的实现会覆盖Object::equalsObject::hashCode查看存储在该对长整数中的数据。这是这两种方法源代码

@Override
public int hashCode() {
    return this.member.hashCode() ;  // Throws NullPointerException if member variable is null.
}
Run Code Online (Sandbox Code Playgroud)
@Override
public int hashCode() {
    return Objects.hashCode( this.member ) ;  // Returns zero (0) if `this.member` is NULL, rather than throwing exception.
}
Run Code Online (Sandbox Code Playgroud)

范例程式码

实例化我们的UUID对象。

UUID uuid = UUID.randomUUID();
Run Code Online (Sandbox Code Playgroud)

计算我们的哈希值。

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.
Run Code Online (Sandbox Code Playgroud)

转储到控制台。

@Override
public int hashCode() {
    return Objects.hash( this.memberA , this.memberB , this.memberC  ) ;  // Hashes the result of all the passed objects’ individual hash codes.  
}
Run Code Online (Sandbox Code Playgroud)

参见IdeOne.com实时运行代码

uuid.toString():401d88ff-c75d-4607-bb89-1f7a2c6963e1

1/2 = 278966883 | 278966883

3/4 = 278966914 | 278966914


ezz*_*een 12

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;
    }
} 
Run Code Online (Sandbox Code Playgroud)

然后创建两个对象:

Car car1 = new Car("Toyota", "Corolla", 2010);
Car car2 = new Car("Toyota", "Corolla", 2010);
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

这将使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);
}
Run Code Online (Sandbox Code Playgroud)

Objects.hash(Object ... values)将为您调用Arrays.hashCode.

最后,Objects.hashCode(Object o)将进行空检查.如果对象为null,它将返回0.否则,它将调用对象hashCode()方法.

  • 默认的 hashCode() 已经有大约 20 年没有返回内存地址了。实在不行啊 GC 移动对象。所谓的内存地址就是不可移动句柄的地址。 (2认同)