Quick Question: If I want to use HashMap with a custom class as the key, must I override the hashCode function? How will it work if I do not override that function?
If you don't override hashCode AND equals you will get the default behaviour which is that each object is different, regardless of its contents.
Technically, you don't have to override the hashCode method as long as equal objects have the same hashCode.
So, if you use the default behaviour defined by Object, where equals only returns true only for the same instance, then you don't have to override the hashCode method.
But if you don't override the equals and the hashCode methods, it means you have to make sure you're always using the same key instance.
E.g.:
MyKey key1_1 = new MyKey("key1");
myMap.put(key1_1,someValue); // OK
someValue = myMap.get(key1_1); // returns the correct value, since the same key instance has been used;
MyKey key1_2 = new MaKey("key1"); // different key instance
someValue = myMap.get(key1_2); // returns null, because key1_2 has a different hashCode than key1_1 and key1_1.equals(key1_2) == false
In practice you often have only one instance of the key, so technically you don't have to override the equals and hashCode methods.
But it's best practice to override the equals and hashCode methods for classes used as keys anyway, because sometime later you or another developer might forget that the same instance has to be used, which can lead to hard to track issues.
And note: even if you override the equals and hashCode methods, you must make sure you don't change the key object in a way that would change the result of the equals or the hashCode methods, otherwise the map won't find your value anymore. That's why it's recommended to use immutable objects as keys if possible.
The only time you don't have to override the hashCode() function is when you also don't override equals, so you use the default Object.equals definition of reference equality. This may or may not be what you want -- in particular, different objects will not be considered equal even if they have the same field values.
If you override equals but not hashCode, HashMap behavior will be undefined (read: it won't make any sense at all, and will be totally corrupted).
It depends on the object class you are using as a key. If it's a custom class like you propose, and it doesn't extend anything (i.e. it extends Object) then the hashCode function will be that of Object, and that will consider memory references, making two objects that look the same to you hash to different codes.
So yes, unless you are extending a class with a hashCode() function you know works for you, you need to implement your own. Also make sure to implement equals(): some classes like ArrayList will only use equals while others like HashMap will check on both hashCode() and equals().
Consider also that if your key is not immutable you may have problems. If you put an entry with a mutable key in the map an you change later the key in a way that it affects hashcode and equals you may lose your entry in the map,as you won't be able to retrieve it anymore.
You should override the equals() and hashCode() methods from the Object class. The default implementation of the equals() and hashcode(), which are inherited from the java.lang.Object uses an object instance’s memory location (e.g. MyObject#6c60f2ea). This can cause problems when two instances of the an objects have the same properties but the inherited equals() will return false because it uses the memory location, which is different for the two instances.
Also the toString() method can be overridden to provide a proper string representation of your object.
primary considerations when implementing a user defined key
If a class overrides equals(), it must override hashCode().
If 2 objects are equal, then their hashCode values must be equal as well.
If a field is not used in equals(), then it must not be used in hashCode().
If it is accessed often, hashCode() is a candidate for caching to enhance performance.
Related
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().
Why does the Hashcode of an Object change in Java? Does it change at all?
How is it related to Hashtable ?
Every object should have it's unique hashcode.So, is Rehashing a reason for it ?
Thanks in advance.
The default implementation of hashcode is equivalent to object identity. However, some objects override hashcode, which might give you a hashcode that changes based on object state.
Usually you do this if you're overriding the definition of equals( in fact, if you override equals you should override hashcode). This is because you want objects that are equal by whatever definition you've created to return the same hashcode. Otherwise you can have a situation a map holds multiple "equal" objects, because they return different hashcodes.
why I need to override for direct access of value in Hash map.That is if insert data into hashmap as follow HashMap,I could get value by giving the Key as Integer ,would get Object as Value.In this case is it necessary to Override equals() and hashCode() method?Please give suggestion.
No, you don't need to override anything to use an object as a value in a HashMap.
Only keys need to have a working hashCode().
However, you need to implement these two methods (technically only equals, but these two are a set, really) if you want to use things like Map#containsValue, List#indexOf or Collection#contains (and these should not just be using reference identity).
hashCode() is used to search for a specific elem when you want to retrieve it from a hashTable. hashCode() doesn't have to be distinct. in fact, you could just return the same integer for all your instance, but then, elems are stored in a list instead of a hashTable, and will cause a performance problem.
By default implementation of hashCode() (which is the implementation of Object for subClass to extents from )of JVM returns a integer according to the memory address of the object, so this should be enough, but this implement was not required by the JVM standard.
By default(Class object), implementation of equals() will return true and only return true when they have same reference , ie obj1 == obj2. read this
keep in mind that:
equal objects must have same hashCode()
those have same hashCode() are not required to be equal to each other.
I think override of hashCode() is not needed in most situations(not extends from other Class), cause modern JVMs has done
pretty good job for you.
So conclusion is:
if your super class have overwrite the hashCode() and equals() method, then you should override them, or at least take a look at the implementation, and decide whether you should override them.
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.
Is there some implementation of java.util.Map that does not uses HashCode?
I have the following problem:
I store an object associated to another object on a HashMap;
Change a property from the key object used on step 1;
As the hashcode is used to store the keys on the regular implementation of HashMap, when I perform a get() on the HashMap, I get null, because the old object hashCode was different at step 1.
Is there a solution for that? Or should I really use just immutable fields for my equals / hashCode methods?
IdentityHashMap uses the Object identity instead of the hashCode; however that does mean that you require the original object used as key to retrieve the value of the map. Other options would be redefine the hashcode to exclude the mutable parts of the object, or - if you can't redefine the hashCode for some reason - wrap the object in another object which provides a stable hashCode.
You would be well advised to use an immutable key, and to re-insert the key/value pair into Map, rather than mutating the key in-place. As you discovered, that just leads to weird bugs.
If this isn't an option for you, then see if you can ignore the mutable property in the hashCode() method, so that the hash code doesn't change. If that's the only property of the class, though, that's not a good idea.
You may be able to get away with using TreeMap, which I don't think uses hashCode(). However, it does require consistency between the key's compareTo() and equals() methods, so you may just end up with the same problem as before if the return values of those methods can change.
All Maps should use immutable objects for keys. True for Python; true for Java.
If you implement equals and hashCode using only immutable fields you should be fine.
How about removing and adding it again ?
On Step 2, You can remove the element added in Step 1 and again add it with new latest properties set. This way when you are try to get in Step 3, you will find it.
Try it.
I think modify the key object in map is not a good practice.
But if you really want, you can override the hashCode() and remember to override the equal() method.
All associative containers use comparing or hash code, so I would like to recommend you using immutable fields for equals() / hashCode() methods.
Override equals and hashCode methods if you don't want original implementation.