Reputation: 2323
I am looking for guidance with regard to overriding both hashcode and equals in a subclass.
I have found a similar question here: Overriding equals() & hashCode() in sub classes ... considering super fields
But what I want is something slightly different.
Imagine this (somewhat stupid) example:
class Food {
String name;
@Override
public boolean equals(Object obj) {
if (obj instanceof Food) {
Food other = (Food)obj;
return name.equals(other.name);
}
return false;
}
@Override
public int hashCode() {
return name.hashCode();
}
}
class Vegetable extends Food {
// No additional fields here
// Some methods here
}
class Fruit extends Food {
// No additional fields here
// Some methods here
}
Given that:
Fruit
and Vegetable
with the same name, should not be equalQuestions:
instanceof
check for the subclass and a call to super.equals
?Fruit
and Vegetable
instances with the same name have different hashcodes?Upvotes: 1
Views: 759
Reputation: 121780
You can just use .getClass()
in Foo
's .equals()
:
@Override
public final boolean equals(final Object obj)
{
if (obj == null)
return false;
if (this == obj)
return true;
// Class<?> are signletons, therefore we can use ==/!=
if (getClass() != obj.getClass())
return false;
return name.equals(((Foo) obj).name);
}
.getClass()
will return the class of the object, therefore Fruit
or Vegetable
, or even Food
.
For .hashCode()
, name.hashCode()
is fine. Don't forget that there is no requirement that the hashcode of two objects which are not .equals()
be different. But if you want to, then .getClass()
can be used here as well:
@Override
public final int hashCode()
{
return 31 * getClass().hashCode() + name.hashCode();
}
Upvotes: 2
Reputation: 37855
- Would you expect the equals to simply contain an instanceof check and a call to super.equals?
instanceof
is dangerous here because Food
is not abstract. This would mean equals
was not symmetric.
someFruit.equals(someFood) // will be false
someFood.equals(someFruit) // will be true
This may not turn in to a problem but it's a thing you should consider.
If you don't want to break the contract, this is a case where Food
should check whether this.getClass() == obj.getClass()
. If you do that then you also don't necessarily need to override it in the subclasses.
Otherwise it doesn't really matter. The method is defined contractually and you can implement it however you want.
- How should the hashcode be structured in an attempt to have Fruit and Vegetable instances with the same name have different hashcodes?
They don't need to be different.
Upvotes: 1