When does the jvm assign hashcode value in the object header - java

I have learned that the java object header contains the information such as hashcode、gc year、biased lock and so on. Then a puzzle come to me and in order express my question explicitly. I give an example.
Here is the code:
public class Demo{
#Override
public int hashCode(){
System.out.println("the hashCode method was called");
return super.hashCode();
}
public static void main(String[] args){
Demo demo = new Demo();
System.out.println("after generate an object");
//
Set<Demo> set = new HashSet<Demo>();
set.add(demo);
}
}
And the output:
after generate an object
the hashCode method was called
I guess when we new an object the jvm will set hashcode in object header. But if this in order to generate hashCode it should be invoke hashCode method of this object.
However according to the output which seemed it havent invoke hashCode method when new an object. And add value into hashSet the hashCode method is invoked, this as was expected.
So my question is that: When does the jvm assign hashcode value in the object header? It happened in the phase when new an object?
If Yes. Why it havent invoke hashcode method, and without this how to calculate hashcode of this object.
If No. Uhhh... It make no sense that update hashcode in object header every invoke invoke hashCode method.

JVM does not need to call hashCode method to initialize object's identity hashCode. It works the other way round: Object.hashCode and System.identityHashCode call JVM to compute or to extract previously computed identity hashCode.
It is not specified how JVM generates and stores identity hashCode. Different JVM implementations may do it differently.
HotSpot JVM computes identity hashCode on the first call to Object.hashCode or System.identityHashCode and stores it in the object header. The subsequent calls simply extract the previously computed value from the header.

I think you are confusing hashcode and identity-hashcode.
An object's hashcode will not be stored in the object header but is computed by calling the hashcode method as needed. In your example hashcode is called because you are adding your object to a HashSet.
The identity hashcode is computed by the JVM at object creation and serves - amongst others - as fallback for an object's hashcode value. That is Object.hashcode() will return the identity hashcode of your object. This value will not change during the lifetime of your object.
See this question for further details.

Related

If the hashcode() creates hashcode based on the address of the object, how can two different objects with same contents create the same hashcode?

When you read the description of hashCode() in the Object class, it says that
If two objects are equal according to the equals(Object) method, then
calling the hashCode method on each of the two objects must produce
the same integer result.
I've read an article and it says that an object's hashcode() can provide different integer values if it runs in different environments even though their content is the same.
It does not happen with String class's hashcode() because the String class's hashcode() creates integer value based on the content of the object. The same content always creates the same hash value.
However, it happens if the hash value of the object is calculated based on its address in the memory. And the author of the article says that the Object class calculates the hash value of the object based on its address in the memory.
In the example below, the objects, p1 and p2 have the same content so equals() on them returns true.
However, how come these two objects return the same hash value when their memory addresses are different?
Here is the example code: main()
Person p1 = new Person2("David", 10);
Person p2 = new Person2("David", 10);
boolean b = p1.equals(p2);
int hashCode1 = p1.hashCode();
int hashCode2 = p2.hashCode();
Here is the overriden hashcode()
public int hashCode(){
return Objects.hash(name, age);
}
Is the article's content wrong?
If there is a hashCode() that calculates a hash value based on the instance's address what is the purpose of them?
Also, if it really exists, it violates the condition that Object class's hashCode() specifies. How should we use the hashCode() then?
I think you have misunderstood this statement:
If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
The word “must” means that you, the programmer, are required to write a hashCode() method which always produces the same hashCode value for two objects which are equal to each other according to their equals(Object) method.
If you don’t, you have written a broken object that will not work with any class that uses hash codes, particularly unsorted Sets and Maps.
I've read an article and it says that an object's hashcode() can provide different integer values if it runs in different environments even though their content is the same.
Yes, hashCode() can provide different values in different runtimes, for a class which does not override the hashCode() method.
… how come these two objects return the same hash value when their memory addresses are different?
Because you told them to. You overrode the hashCode() method.
If there is a hashCode() that calculates a hash value based on the instance's address what is the purpose of them?
It doesn’t have a lot of use. That’s why programmers are strongly recommended to override the method, unless they don’t care about object identity.
Also, if it really exists, it violates the condition that Object class's hashCode() specifies. How should we use the hashCode() then?
No it does not. The contract states:
Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.
As long as the hashCode method defined in the Object class returns the same value for the duration of the Java runtime, it is compliant.
The contract also says:
If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
Two objects whose equals method reports that they are effectively equal must return the same hashCode. Any instance of the Object class whose type is not a subclass of Object is only equal to itself and cannot be equal to any other object, so any value it returns is valid, as long as it is consistent throughout the life of the Java runtime.
The article is wrong, memory address is not involved (btw. the address can change during the lifecycle of objects, so it's abstracted away as a reference). You can look at the default hashCode as a method that returns a random integer, which is always the same for the same object.
Default equals (inherited from Object) works exactly like ==. Since there is a condition (required for classes like HashSet etc. to work) that states when a.equals(b) then a.hashCode == b.hashCode, then we need a default hashCode which only has to have one property: when we call it twice, it must return the same number.
The default hashCode exists exactly so that the condition you mention is upheld. The value returned is not important, it's only important that it never changes.
No p1 and p2 does not have the same content
If you do p1.equals(p2) that will be false, so not the same content.
If you want p1 and p2 to equal, you need to implement the equals methods from object, in a way that compare their content. And IF you implement the equals method, then you also MUST implement the hashCode method, so that if equals return true, then the objects have the same hashCode().
Here's the design decision every programmer needs to make for objects they define of (say) MyClass:
Do you want it to be possible for two different objects to be "equal"?
If you do, then firstly you have to implement MyClass.equals() so that it gives the correct notion of equality for your purposes. That's entirely in your hands.
Then you're supposed to implement hashCode such that, if A.equals(B), then A.hashCode() == B.hashCode(). You explicitly do not want to use Object.hashCode().
If you don't want different objects to ever be equal, then don't implement equals() or hashCode(), use the implementations that Object gives you. For Object A and Object B (different Objects, and not subclasses of Object), then it is never the case that A.equals(B), and so it's perfectly ok that A.hashCode() is never the same as B.hashCode().

Wrapper class strange behaviour in java

public class Test {
public static void main(String args[]) {
int i = 10;
Integer a = new Integer(i);
System.out.println(a); //tostring method overriden
System.out.println(a.hashCode());
}
}
Output:
10
10
now my question is why hashCode() method is overriden in this case.
If I want to find the object reference of the wrapper class object a in the above code.
How do i do it?
The object reference to the integer in your case is a. Unlike C, in Java, you can't get a reference pointer to an object. The hashCode is not used to identify the address location of an object in the memory.
From the hashCode API,
Returns a hash code value for the object. This method is supported for the benefit of hash tables such as those provided by HashMap.
As it turns out, the most efficient value of hashCode for an integer is the value itself.
If you still want to get hold of the original hash value of the object, I would suggest using the System.identityHashCode method.
System.identityHashCode(a)
my question is why hashCode method is overriden in this case
Wrappers, like String, are immutable. Said this, if every different object of a class has a different value (state), that value is a perfect hash code: zero collisions, total entropy, homogeneus distribution...
If i want to find the object reference of the wrapper class object a
in the above code.How do i do it?
Using System.identityHashCode()
In Java, hashcode helps to give a quick comparaison hint between two objects. As two different Integer having same value are equal, they should have same hash. That's the reason why the value was taken for hash.

Questions about contains method in Hash Set

I am a high school student so I apologize for the terms I may misuse.
So I am making a slide puzzle game and working on the AI part. So I have a constructor that construct board and assign its hashcode such as 123456780. In my A* algorithm, I compare if the board that I generate (to find the solution) is already in the hashset. So I use contains method for it right? but how does the contains method works to check if the two boards are identical?.
public Board()
{
board = new int [3][3];
setPieces (board);
hashCode = generateHashCode ();
}
This is one of my constructor. In my board object, I have 2D array and the hashcode. But I wonder again, if the built-in contains method in Hash Set compare two boards hashcode. Or I need to write one.
Also, when I assign the hash code to a board, I should do it in my constructor right?
Thanks you
As you've discovered, you need to return a hashcode for your object in the overridden hashCode() method.
You can either compute a hashcode in that method, or compute it in the ctor and store it in a field, then return the field in the method override.
Any collection that uses the 'Hash' prefix has all objects contained within the collection stored in groups by their hashcode. So when you call a method like contains() the collection loops through each hashcode group and checks whether the hashcode of the object you parsed in matches the group. When a match is found, the objects within that hashcode group are checked using the equals() method of the stored object until an Object's equals() method returns true.
If you do not override the hashcode() method, then each Object subclass is given a more or less unique hashcode by the Object class implementation of the hashcode() method. This can cause some problems if you have already overridden the equals() method, because if two objects are considered equal the contains() method might still not find it if the hashcodes do not match.
The hashcode contract:
When implementing hashcode() the Java Object API has laid out a contract or a set of specifications on how you should implement the hashcode method. And they are;
If hashcode() is run on an object multiple times, it must always return the same number.
If two objects are considered equal by the equals() method then their hashcode() methods must return the same value.
If two objects have the same hashcode, they do not have to be considered equal by their equals() methods.
References:
The hashcode contract.
Implementing hashcode.

Java Mutable Object as Map Key but using default hashCode()

I understand using immutable object as map keys are preferable. But how about mutable objects with default hashCode() method (and of course, I don't override the equals() method). That should also be fine, since default hashCode() uses the object memory address?
Is there anything I miss here?
So long as the hashCode and equals method always return the same result it is safe to use the object as the key in the HashMap.
However you are probably reducing their utility as a key by doing so! The whole point of equals/hashCode is to identify equality between object values, and if you modify the members of an object is it really equal to how it was before the modification?
Below is hash code with string. However, an issue to worry about is the possible change of implementation between early/late versions of Java of string hash code.
public int hashCode()
{
return "name".hashCode();
}
In addition, there is an article hash collision probabilities
Mutuable Objects as a Key with default equals() and hashcode() is of no use..
e.g
map.put(new Object() , "value") ;
when you want to get that value ,
map.get(new Object()) ; // This will always return null
Because with new Object() - new hashcode will be generated and it will not point to the expected bucket number on which value is saved, and if eventually bucket number comes to be same - it won't be able to match hashcode and even equals so it always return NULL

HashMap Not Calling Object.equals?

I wrote a class that overrides the equals(Object) method in class Object to compare objects of the class type to other objects of a class type using the object's instance values.
When I put an instance of the object in a HashMap as the key, and then call get(Object) on the map with a new but identical object as the key, it returns null.
I've tried passing a new, identical object to the equals method and it returns true, so the problem isn't my comparison code.
From what I've gathered through debugging, the equals(Object) method in my object is never called.
But if you use a String key in a HashMap and then pass a new instance with identical characters to get(Object), it returns the value successfully.
Why is this happening? What do I have to do to have HashMap test keys based on MY equals method?
You need to also override Object.hashcode(). Take a look at the link, as it specifies that hashcode() and equals() have a contract to ensure proper functionality in HashTable's, HashMap's, and HashSet's.
In a HashMap, values are stored in buckets, which are reached by the hashcode of the key. Once the proper bucket is found, the equals method is then applied to each member of the bucket until equality is determined. Because of this, it is important to make sure that your hash algorithm 'hashes well'.
You should also override hashCode otherwise it won't work as HashMap (as the name suggests) equates equality based on a collection of hashes. The Java "honour code" for overriding equals is that you should also override hashCode at the same time.

Categories