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

问题描述 投票:48回答:3

在Java 7中我们有

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

    Objects.hash(o);

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

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

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

hashcode java-7
3个回答
72
投票

请参阅hashCodehash的文档。 hash采取Object...hashCode采取Object。给出的例子是:

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

请注意,hash(o)hashCode(o)不一定会返回相同的东西!如果你是为一个对象做的,你应该使用hashCode


12
投票

Objects.hashCode

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

容忍NULL

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

这种方法有一个好处:NULL0。该实用方法容许null。

  • 如果你打电话给Objects.hashCode( myObject ),其中myObjectNULL,你会得到一个零(0)。
  • 相反,当myObject.hashCode()myObject时,调用NULL引发了NullPointerException论点。

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

Objects.hash

实用方法Objects.hash( Object o , … )有不同的用途。这种方法有两个阶段:

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

散列的哈希值

如果传递单个对象Objects.hash( myObject ),则首先调用并收集myObject.hashCode,然后计算该单项集合的哈希值。所以,你最终得到一个散列的hash

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

Annoying in practice

这两种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.
}

单个成员,容忍NULL

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

多成员,容忍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.  
}

Example

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

UUID

我们以UUID对象为例。 UUID(通用唯一标识符)是128位值,其中某些位具有某些语义。

UUID的OpenJDK实现在内部将128位值表示为一对64位long整数。

同样的实现覆盖了Object::equalsObject::hashCode来查看存储在那对长整数中的数据。这是source code for those two methods

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);
}
public int hashCode() {
    long hilo = mostSigBits ^ leastSigBits;
    return ((int)(hilo >> 32)) ^ (int) hilo;
}

示例代码

实例化我们的UUID对象。

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.

转储到控制台。

System.out.println( "uuid.toString(): " + uuid.toString() );
System.out.println( " 1/2 = " + hash1 + " | " + hash2 );
System.out.println( " 3/4 = " + hash3 + " | " + hash4 );

看到这个code run live at IdeOne.com

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

1/2 = 278966883 | 278966883

3/4 = 278966914 | 278966914


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()方法。

© www.soinside.com 2019 - 2024. All rights reserved.