I have a class Student and Marks.
I am using Student
Object
as Key for HashMap
and Marks as Value.
If I don't override hashMap
and equals, It still works fine.
i. Can someone please explain how does it internally works on it if not overriding both equals()
and hashcode()
ii. what If I override only hashcode()
iii.what If I override only equals()
class Student {
String name;
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
String lastName;
Student(String name, String lastName){
this.name = name;
this.lastName = lastName;
}
public String toString(){
return(" Name : " + this.getName() + " Last Name : " + this.getLastName());
}
}
class Marks {
Student s;
String marks;
public Student getS() {
return s;
}
public void setS(Student s) {
this.s = s;
}
public String getMarks() {
return marks;
}
public void setMarks(String marks) {
this.marks = marks;
}
Marks (Student s, String marks){
this.marks = marks;
this.s = s;
}
public String toString(){
return(" Marks : " + this.getMarks());
}
}
public class Main {
public static void main(String[] args) {
Student s1 = new Student("Vishnu","Verma");
Student s2 = new Student("Amit","Sharma");
Marks m1 = new Marks(s1,"65%");
Marks m2 = new Marks(s2,"67%");
Map <Student,Marks>map = new HashMap<Student,Marks>();
map.put(s1, m1);
map.put(s2, m2);
System.out.println(map);
}
}
If you don't override equals and hashcode, the implementation is inherited from Object.
The method hashcode() is used by a HashMap to determine in a which sublist the entry will be in. So if you don't override (or even worse, override and give back the same value for each instance) the method, HashMap might store every entry in the same sublist. This will make the map slower, but putting in values will still work.
For your last question see https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#hashCode--
Long story short: You shouldn't override just one. You should override both.
It will consider the objects equal if their references are equal. i.e. they point to the same object.
Let us review how a
HashMap
works (in a simplistic case).First we create our hash table:
When we add a key -> value mapping to our
HashMap
we:hashCode
of the keyhashCode
and the above hash table we select a bucketTo get a value by key from our
HashMap
we:hashCode
of the keyhashCode
and the above hash table we select a bucketequals
to the requested key, if so we return the valueequals
the requested key and return its valuenull
.So, to answer your questions:
how does it internally works on it if not overriding both
equals()
andhashcode()
?I assume you mean if you do not override anything and leave it to the default behaviour.
In this case the
HashMap
usesObject.hashCode
andObject.equals
; theHashMap
will behave exactly like anIdentityHashMap
- i.e. it will useSystem.identityHashCode
to calculate thehashCode
and it will use==
to test for equality.This default behaviour will only work correctly when dealing with the same instance of a
class
.what If I override only
hashcode()
?TL;DR: Your
HashMap
will behave as above.You
hashCode
will be used to select a bucket at insertion (2) and during retrieval (2) but the defaultequals
will be used to determine whether the correct key is found.It is likely that the
Map
will work similarly to the above case, as yourhashCode
implementation is unlikely to break the general contract ofhashCode
, i.e. only the exact same instance will be equal to itself and ifhashCode
compiles with the fact that it must return the same value when it is invoked multiple times on the same instance it must by extension comply with this requirement.NB: The converse is not true. Overriding only
equals
immediately breaks the contract ofhashCode
due to items that areequals
returning different hashcodes. This will break any hash based collection fromHashMap
toHashSet
because you will have duplicate keys and the collection will exhibit Undefined Behaviour.This issue will be that there are many more objects that you will return the same
hashCode
for than objects that you considerequals
- whilst this is part of the very nature of hashing, you will compound this problem.It is likely that your
HashMap
will be inefficient in this case.To illustrate what I mean consider this simple example of a
class
with one element:If we use the default
equals
andhashCode
then the ourMap
would exhibit the following behaviour:i.e. the
Map
will only consider two keys that are==
(such asa
andb
) to be the same.If you ever "lose" a reference to a key instance you will never be able to get it back. So if you did:
You would never, without looping over the
Map
, be able to get "C" out of theMap
again.OP asks: And How we determine only hashCode() need to be overridden or only equals() need to be overridden?
You should only every override both or neither of these methods.
There is never a use case for overriding only
equals
or onlyhashCode
.If not implemented in your class, then
hashCode
andequals
fallback to theObject
implementations which are:So the implementation of
hashCode
varies depending on the runtime environment but more interestingly regardingHashMap
, theequals
methods require the two objects to be the same instance to be equal!Object
cannot guess for you what makes two instances equal so it defaults to the strongest constraint.