Note that the parameter of Objects.hash is Object.... This has two main consequences:
- Primitive values used in the hash code calculation have to be boxed, e.g.
this.idis converted fromlongtoLong. - An
Object[]has to be created to invoke the method.
The cost of creating of these "unnecessary" objects may add up if hashCode is called frequently.
What exactly is an objects hash code?
What's the implementation of hashCode in java Object? - Stack Overflow
java 7 - Objects.hash() vs Objects.hashCode(), clarification needed - Stack Overflow
Can someone ELI5 the hashcode() method for me?
Videos
Note that the parameter of Objects.hash is Object.... This has two main consequences:
- Primitive values used in the hash code calculation have to be boxed, e.g.
this.idis converted fromlongtoLong. - An
Object[]has to be created to invoke the method.
The cost of creating of these "unnecessary" objects may add up if hashCode is called frequently.
Following is implementation of Objects.hash - which is calling Arrays.hashCode internally.
public static int hash(Object... values) {
return Arrays.hashCode(values);
}
This is implementation of Arrays.hashCode method
public static int hashCode(Object a[]) {
if (a == null)
return 0;
int result = 1;
for (Object element : a)
result = 31 * result + (element == null ? 0 : element.hashCode());
return result;
}
So I agree with @Andy The cost of creating of these "unnecessary" objects may add up if hashCode is called frequently. If you are implementing yourself it would be faster.
I was completing a Kotlin topic on Jetbrains Academy about toString() and came across a section saying this about it:
However, for most classes, by default,
toString()still returns the name of the class and the address where the object is located in the memory.
I'm assuming that toString() in Kotlin functions the same way as it does in Java. In Java it takes the name of the objects class and appends the hash code to it which seems to be what is explained above. The only issue I have is that I never heard of an objects hash code being its physical location in memory or the JVM.
How true is this?
hashCode is a native method which means that a system library is called internally. See Java Native Interface for more details.
There is a question on SO Why hashCode() and getClass() are native methods? Might be interesting for you.
The default hashCode is going to be implementation-specific. I suspect it's related to the memory address, but note that the VM moves objects around in memory (and, of course, the hashCode has to remain the same). So it won't be the actual memory address.
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 ownhashCodemethod 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.
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: NULL ➙ 0. The utility method tolerates a null.
- If you call
Objects.hashCode( myObject )wheremyObjectisNULL, you get back a zero (0). - In contrast, calling
myObject.hashCode()whenmyObjectisNULLthrows aNullPointerExceptionargument.
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
.hashCodeon 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(andequals) override is based on a single member of your class, useObjects.hashCode( member ). - If your
hashCode(andequals) override is based on multiple attribute of your class, useObjects.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