Override equals and hashCode
If you want to customize the equals method of an object the
general pattern for doing so is the following.
First, declare an equals method that matches the one that comes from Object.
Don't forget @Override.
class Position {
int x;
int y;
@Override
public boolean equals(Object o) {
}
}
This definition of equals accepts any Object as an argument. Therefore we first
need to make sure that the class of that Object is the same as the class you are
comparing it to.
class Position {
int x;
int y;
@Override
public boolean equals(Object o) {
if (o instanceof Position otherPosition) {
}
else {
return false;
}
}
}
Then you compare all the fields to make sure they are equal to each other as well.
class Position {
int x;
int y;
@Override
public boolean equals(Object o) {
if (o instanceof Position otherPosition) {
return this.x == otherPosition.x && this.y == otherPosition.y;
}
else {
return false;
}
}
}
How you do those comparisons depends on what is in the fields. For int and such you can use ==. For fields
like String you need to use .equals.
class Tree {
String barkDescription;
@Override
public boolean equals(Object o) {
if (o instanceof Tree otherTree) {
//
return this.barkDescription.equals(otherTree.barkDescription);
}
else {
return false;
}
}
}
If you anticipate, or don't take actions to prevent, a field potentially being null
then instead of a.equals(b) use java.util.Objects.equals. All it does special is handle
null without crashing.
import java.util.Objects;
class Tree {
String barkDescription;
@Override
public boolean equals(Object o) {
if (o instanceof Tree otherTree) {
return Objects.equals(otherTree.barkDescription);
}
else {
return false;
}
}
}
Whenever you override equals you are supposed to override hashCode as well.
This is because - by default - every Object is going to give a hashCode consistent
with the default equals method. If you change how equals works, then you could
violate the contract of "if hashCode gives a different value, they definitely aren't equal."
Some parts of Java will rely on that, so its worth addressing.
If you define your equals method as above - essentially "they are equal if all their fields are equal" - then you can use java.util.Objects.hash to define your hashCode.1
import java.util.Objects;
class Position {
int x;
int y;
@Override
public boolean equals(Object o) {
if (o instanceof Position otherPosition) {
return this.x == otherPosition.x && this.y == otherPosition.y;
}
else {
return false;
}
}
@Override
public int hashCode() {
// Just give it all the fields you have.
return Objects.hash(this.x, this.y);
}
}
-
If you defined a more exotic form of
equalsthen how to properly make ahashCodeis an exercise for you, the reader. If you give up thenreturn 1;will always be "correct," if not ideal for the code that useshashCodeas a quick "might be equal" check. ↩