Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Objects.hash() vs Objects.hashCode(), clarification needed

Since Java 7, we have

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

The first two are roughly the same with the null check, but what is last one?

When a single object reference is supplied, the returned value does not equal the hash code of that object reference.

Why is that? I mean, we don't need three methods that do the same thing, I understand that, but why do we need Objects.hash() at all? When would you chose to use one over another?

like image 680
James Raitsev Avatar asked Jul 22 '12 02:07

James Raitsev


People also ask

Should I use objects hash?

hashCode(Object o) should be used when you want the hash of a single object, without throwing if the object is null.

What happens if we do not override hashCode () and equals () in Hashmap?

If you don't override hashcode() then the default implementation in Object class will be used by collections. This implementation gives different values for different objects, even if they are equal according to the equals() method.

What is hashCode () in object class?

Java Object hashCode() is a native method and returns the integer hash code value of the object. The general contract of hashCode() method is: Multiple invocations of hashCode() should return the same integer value, unless the object property is modified that is being used in the equals() method.

Can hashCode be same for the different objects?

1) If two objects are equal (i.e. the equals() method returns true), they must have the same hashcode. 2) If the hashCode() method is called multiple times on the same object, it must return the same result every time. 3) Two different objects can have the same hash code.


3 Answers

See the documentation for hashCode and hash. hash takes Object... while hashCode takes Object. The example given is:

@Override public int hashCode() {
    return Objects.hash(x, y, z);
}
  • Objects.hash(Object... values) should be used in cases when you want a hash of a sequence of objects, e.g. when defining your own hashCode method and want a simply-coded hash for multiple values that make up the identity of your object.
  • Objects.hashCode(Object o) should be used when you want the hash of a single object, without throwing if the object is null.
  • Object::hashCode() should be used when you want the hash of a single object, and will throw an exception if the object is null.

Note that hash(o) and hashCode(o) won't necessarily return the same thing! If you're doing it for a single object, you should probably use hashCode.

like image 79
Tim S. Avatar answered Oct 09 '22 02:10

Tim S.


Objects.hashCode

The utility method Objects.hashCode( Object o ) simply calls the hashCode method on the passed object.

Tolerates NULL

So why invent or use this method? Why not just call the object’s hashCode method yourself?

This method offers one benefit: NULL0. The utility method tolerates a null.

  • If you call Objects.hashCode( myObject ) where myObject is NULL, you get back a zero (0).
  • In contrast, calling myObject.hashCode() when myObject is NULL throws a NullPointerException argument.

Whether tolerating a null is desirable or not depends on your own judgement in your particular situation.

Objects.hash

The utility method Objects.hash( Object o , … ) serves a different purpose. This method has two phases:

  • Call .hashCode on each passed object, collecting each result.
  • Calculate a hash on the collected results.

hash of a hash

If you pass a single object, Objects.hash( myObject ), first myObject.hashCode is called and collected, and then a hash on that single-item collection is calculated. So, you end up with a hash of a hash.

When hashing a single object, it is vital to understand that Objects.hashCode( myObject ) returns a different result than Objects.hash( myObject ). Effectively, the second returns a hash on the result of the first.

Annoying in practice

The logic of the approach taken in these two Objects methods makes sense, in and of themselves.

Unfortunately, in practice, for those of us trying to use them in day-to-day use when writing code on our POJOs to override hashCode, and correspondingly equals, we must think twice to decide which to call.

  • If your hashCode (and equals) override is based on a single member of your class, use Objects.hashCode( member ).
  • If your hashCode (and equals) override is based on multiple attribute of your class, use Objects.hash( memberA , memberB , memberC ).

Single member, not tolerating a NULL

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

Single member, tolerating a NULL

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

Multi-member, tolerating a 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

We can test these various methods quite simply.

UUID

Let's use a UUID object as an example. A UUID (universally unique identifier) is a 128-bit value where certain bits have certain semantics.

The OpenJDK implementation of UUID internally represents the 128-bit value as a pair of 64-bit long integer numbers.

That same implementation overrides Object::equals and Object::hashCode to look at the data stored in that pair of long integers. Here is the 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;
}

Example code

Instantiate our UUID object.

UUID uuid = UUID.randomUUID();

Calculate our hash values.

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.

Dump to console.

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

See this code run live at IdeOne.com.

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

1/2 = 278966883 | 278966883

3/4 = 278966914 | 278966914

like image 27
Basil Bourque Avatar answered Oct 09 '22 00:10

Basil Bourque


The default hashCode() of Object returns the memory address for the object. So if you have the following class:

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;
    }
} 

then create two objects:

Car car1 = new Car("Toyota", "Corolla", 2010);
Car car2 = new Car("Toyota", "Corolla", 2010);

car1.hashCode() will be different from car2.hashCode() because each object will have a different memory address.

What if you want both car1 and car2 to return the same hash code? In this case, you should override the default Object hashCode() method for the Car class as follows:

@Override
public int hashCode() {
    Object[] x = {model, make, Integer.valueOf(year)};
    int hashArray = Arrays.hashCode(x);
    return hashArray;
}

This will make car1.hashCode() equal to car2.hashCode() because the String.hashCode() calculates the hashCode based on the string contents, and the Integer.hashCode() will return the integer value itself.

In Java 7, you can just use Objects.hash(Object... values). So our new Car hashCode() will look as follows:

@Override
public int hashCode() {
    return Objects.hash(model, make, year);
}

Objects.hash(Object... values) will call Arrays.hashCode for you.

Finally, Objects.hashCode(Object o) will do a null check. It will return 0 if the object is null. Else, it will call the objects hashCode() method.

like image 15
ezzadeen Avatar answered Oct 09 '22 02:10

ezzadeen