What is the proper way to implement a robust equals() and hashCode() method in an inheritance hierarchy?
I have the following abstract Person
class:
import java.util.Objects;
public abstract class Person
protected String name;
protected int id;
public Person(String name, int id)
this.name = name;
this.id = id;
public abstract String description();
@Override
public boolean equals(Object obj)
if(this == obj) return true;
if(!(obj instanceof Person)) return false;
return Objects.equals(this.name, ((Person) obj).name) &&
this.id == ((Person) obj).id;
@Override
public int hashCode()
return Objects.hash(this.name, this.id);
And Now I have a subclass of Person
called Employee
:
import java.time.LocalDate;
import java.util.Objects;
public class Employee extends Person {
private double salary;
private LocalDate hireDay;
public Employee(String name, int id, double salary, int year, int month, int day)
super(name, id);
this.salary = salary;
this.hireDay = LocalDate.of(year, month, day);
@Override
public String description()
return "Employee with a salary of " + this.salary;
@Override
public int hashCode()
return super.hashCode() + Objects.hash(this.salary,this.hireDay);
@Override
public boolean equals(Object obj)
return super.equals(obj) &&
Double.compare(this.salary, ((Employee) obj).salary) == 0
&& Objects.equals(this.hireDay,((Employee)obj).hireDay);
To implement an equals method properly, it must conform to the following contract.
Reflextive: x.equals(x) is always True
Symmetric: x.equals(y) is equivalent to y.equals(x)
Transitive: x.equals(y) and y.equals(z) implies x.equals(z) is true
When I call the equals() method of the superclass inside the subclass, I first ensure that all objects being compared are subclasses of the superclass. This issue resolves the problem of comparing mixed-types and takes care of the contract mentioned above. I no longer have to use the following implementation of equals:
@Override
public boolean equals(Object obj) this.getClass() != obj.getClass()) return false;
Employee other = (Employee) obj;
return Objects.equals(this.name, other.name) &&
Double.compare(this.salary, other.salary) == 0 &&
Objects.equals(this.hireDay, other.hireDay);
Namely, I no longer have to check explicitly whether the current object (this
) is of the same class as obj
because of the method in the superclass that uses the instance of
operator.
Is it more robust to put that implementation in the equals operator of the superclass or is it better to use the more explicit test in the subclass using the getClass()
method in order to conform to the contract?
In terms of the hashCode() method, I hash the private instance fields specific to the subclass and simply add that to the result of the hash method in the superclass. I couldn't find any documentation that shows whether or not this is the proper way to implement the hashCode() function in general or in an inheritance hierarchy. I have seen code where people have explicitly specified their own hash functions.
I apologize if my questions are too general but I tried my best to ask them without being too ambiguous.
EDIT:
I asked Intellij to implement an equals and hashcode method and it decided to go with the last implementation that I posted above. Then, under what circumstances would I use instance of
in the superclass? Would it be when I'm implementing a final equals method in the superclass such as only comparing Person objects based on user id?
java inheritance equals hashcode
add a comment |
I have the following abstract Person
class:
import java.util.Objects;
public abstract class Person
protected String name;
protected int id;
public Person(String name, int id)
this.name = name;
this.id = id;
public abstract String description();
@Override
public boolean equals(Object obj)
if(this == obj) return true;
if(!(obj instanceof Person)) return false;
return Objects.equals(this.name, ((Person) obj).name) &&
this.id == ((Person) obj).id;
@Override
public int hashCode()
return Objects.hash(this.name, this.id);
And Now I have a subclass of Person
called Employee
:
import java.time.LocalDate;
import java.util.Objects;
public class Employee extends Person {
private double salary;
private LocalDate hireDay;
public Employee(String name, int id, double salary, int year, int month, int day)
super(name, id);
this.salary = salary;
this.hireDay = LocalDate.of(year, month, day);
@Override
public String description()
return "Employee with a salary of " + this.salary;
@Override
public int hashCode()
return super.hashCode() + Objects.hash(this.salary,this.hireDay);
@Override
public boolean equals(Object obj)
return super.equals(obj) &&
Double.compare(this.salary, ((Employee) obj).salary) == 0
&& Objects.equals(this.hireDay,((Employee)obj).hireDay);
To implement an equals method properly, it must conform to the following contract.
Reflextive: x.equals(x) is always True
Symmetric: x.equals(y) is equivalent to y.equals(x)
Transitive: x.equals(y) and y.equals(z) implies x.equals(z) is true
When I call the equals() method of the superclass inside the subclass, I first ensure that all objects being compared are subclasses of the superclass. This issue resolves the problem of comparing mixed-types and takes care of the contract mentioned above. I no longer have to use the following implementation of equals:
@Override
public boolean equals(Object obj) this.getClass() != obj.getClass()) return false;
Employee other = (Employee) obj;
return Objects.equals(this.name, other.name) &&
Double.compare(this.salary, other.salary) == 0 &&
Objects.equals(this.hireDay, other.hireDay);
Namely, I no longer have to check explicitly whether the current object (this
) is of the same class as obj
because of the method in the superclass that uses the instance of
operator.
Is it more robust to put that implementation in the equals operator of the superclass or is it better to use the more explicit test in the subclass using the getClass()
method in order to conform to the contract?
In terms of the hashCode() method, I hash the private instance fields specific to the subclass and simply add that to the result of the hash method in the superclass. I couldn't find any documentation that shows whether or not this is the proper way to implement the hashCode() function in general or in an inheritance hierarchy. I have seen code where people have explicitly specified their own hash functions.
I apologize if my questions are too general but I tried my best to ask them without being too ambiguous.
EDIT:
I asked Intellij to implement an equals and hashcode method and it decided to go with the last implementation that I posted above. Then, under what circumstances would I use instance of
in the superclass? Would it be when I'm implementing a final equals method in the superclass such as only comparing Person objects based on user id?
java inheritance equals hashcode
@4castle Well, wouldn't the superclass equals() method take care of that assuming short-circuit evaluation? It would return false before even getting to the cast.
– Mutating Algorithm
Nov 14 '18 at 0:25
Why doesEmployee.equals()
cast without checking the type?
– shmosel
Nov 14 '18 at 0:26
add a comment |
I have the following abstract Person
class:
import java.util.Objects;
public abstract class Person
protected String name;
protected int id;
public Person(String name, int id)
this.name = name;
this.id = id;
public abstract String description();
@Override
public boolean equals(Object obj)
if(this == obj) return true;
if(!(obj instanceof Person)) return false;
return Objects.equals(this.name, ((Person) obj).name) &&
this.id == ((Person) obj).id;
@Override
public int hashCode()
return Objects.hash(this.name, this.id);
And Now I have a subclass of Person
called Employee
:
import java.time.LocalDate;
import java.util.Objects;
public class Employee extends Person {
private double salary;
private LocalDate hireDay;
public Employee(String name, int id, double salary, int year, int month, int day)
super(name, id);
this.salary = salary;
this.hireDay = LocalDate.of(year, month, day);
@Override
public String description()
return "Employee with a salary of " + this.salary;
@Override
public int hashCode()
return super.hashCode() + Objects.hash(this.salary,this.hireDay);
@Override
public boolean equals(Object obj)
return super.equals(obj) &&
Double.compare(this.salary, ((Employee) obj).salary) == 0
&& Objects.equals(this.hireDay,((Employee)obj).hireDay);
To implement an equals method properly, it must conform to the following contract.
Reflextive: x.equals(x) is always True
Symmetric: x.equals(y) is equivalent to y.equals(x)
Transitive: x.equals(y) and y.equals(z) implies x.equals(z) is true
When I call the equals() method of the superclass inside the subclass, I first ensure that all objects being compared are subclasses of the superclass. This issue resolves the problem of comparing mixed-types and takes care of the contract mentioned above. I no longer have to use the following implementation of equals:
@Override
public boolean equals(Object obj) this.getClass() != obj.getClass()) return false;
Employee other = (Employee) obj;
return Objects.equals(this.name, other.name) &&
Double.compare(this.salary, other.salary) == 0 &&
Objects.equals(this.hireDay, other.hireDay);
Namely, I no longer have to check explicitly whether the current object (this
) is of the same class as obj
because of the method in the superclass that uses the instance of
operator.
Is it more robust to put that implementation in the equals operator of the superclass or is it better to use the more explicit test in the subclass using the getClass()
method in order to conform to the contract?
In terms of the hashCode() method, I hash the private instance fields specific to the subclass and simply add that to the result of the hash method in the superclass. I couldn't find any documentation that shows whether or not this is the proper way to implement the hashCode() function in general or in an inheritance hierarchy. I have seen code where people have explicitly specified their own hash functions.
I apologize if my questions are too general but I tried my best to ask them without being too ambiguous.
EDIT:
I asked Intellij to implement an equals and hashcode method and it decided to go with the last implementation that I posted above. Then, under what circumstances would I use instance of
in the superclass? Would it be when I'm implementing a final equals method in the superclass such as only comparing Person objects based on user id?
java inheritance equals hashcode
I have the following abstract Person
class:
import java.util.Objects;
public abstract class Person
protected String name;
protected int id;
public Person(String name, int id)
this.name = name;
this.id = id;
public abstract String description();
@Override
public boolean equals(Object obj)
if(this == obj) return true;
if(!(obj instanceof Person)) return false;
return Objects.equals(this.name, ((Person) obj).name) &&
this.id == ((Person) obj).id;
@Override
public int hashCode()
return Objects.hash(this.name, this.id);
And Now I have a subclass of Person
called Employee
:
import java.time.LocalDate;
import java.util.Objects;
public class Employee extends Person {
private double salary;
private LocalDate hireDay;
public Employee(String name, int id, double salary, int year, int month, int day)
super(name, id);
this.salary = salary;
this.hireDay = LocalDate.of(year, month, day);
@Override
public String description()
return "Employee with a salary of " + this.salary;
@Override
public int hashCode()
return super.hashCode() + Objects.hash(this.salary,this.hireDay);
@Override
public boolean equals(Object obj)
return super.equals(obj) &&
Double.compare(this.salary, ((Employee) obj).salary) == 0
&& Objects.equals(this.hireDay,((Employee)obj).hireDay);
To implement an equals method properly, it must conform to the following contract.
Reflextive: x.equals(x) is always True
Symmetric: x.equals(y) is equivalent to y.equals(x)
Transitive: x.equals(y) and y.equals(z) implies x.equals(z) is true
When I call the equals() method of the superclass inside the subclass, I first ensure that all objects being compared are subclasses of the superclass. This issue resolves the problem of comparing mixed-types and takes care of the contract mentioned above. I no longer have to use the following implementation of equals:
@Override
public boolean equals(Object obj) this.getClass() != obj.getClass()) return false;
Employee other = (Employee) obj;
return Objects.equals(this.name, other.name) &&
Double.compare(this.salary, other.salary) == 0 &&
Objects.equals(this.hireDay, other.hireDay);
Namely, I no longer have to check explicitly whether the current object (this
) is of the same class as obj
because of the method in the superclass that uses the instance of
operator.
Is it more robust to put that implementation in the equals operator of the superclass or is it better to use the more explicit test in the subclass using the getClass()
method in order to conform to the contract?
In terms of the hashCode() method, I hash the private instance fields specific to the subclass and simply add that to the result of the hash method in the superclass. I couldn't find any documentation that shows whether or not this is the proper way to implement the hashCode() function in general or in an inheritance hierarchy. I have seen code where people have explicitly specified their own hash functions.
I apologize if my questions are too general but I tried my best to ask them without being too ambiguous.
EDIT:
I asked Intellij to implement an equals and hashcode method and it decided to go with the last implementation that I posted above. Then, under what circumstances would I use instance of
in the superclass? Would it be when I'm implementing a final equals method in the superclass such as only comparing Person objects based on user id?
java inheritance equals hashcode
java inheritance equals hashcode
edited Nov 14 '18 at 1:01
Mutating Algorithm
asked Nov 14 '18 at 0:19
Mutating AlgorithmMutating Algorithm
838628
838628
@4castle Well, wouldn't the superclass equals() method take care of that assuming short-circuit evaluation? It would return false before even getting to the cast.
– Mutating Algorithm
Nov 14 '18 at 0:25
Why doesEmployee.equals()
cast without checking the type?
– shmosel
Nov 14 '18 at 0:26
add a comment |
@4castle Well, wouldn't the superclass equals() method take care of that assuming short-circuit evaluation? It would return false before even getting to the cast.
– Mutating Algorithm
Nov 14 '18 at 0:25
Why doesEmployee.equals()
cast without checking the type?
– shmosel
Nov 14 '18 at 0:26
@4castle Well, wouldn't the superclass equals() method take care of that assuming short-circuit evaluation? It would return false before even getting to the cast.
– Mutating Algorithm
Nov 14 '18 at 0:25
@4castle Well, wouldn't the superclass equals() method take care of that assuming short-circuit evaluation? It would return false before even getting to the cast.
– Mutating Algorithm
Nov 14 '18 at 0:25
Why does
Employee.equals()
cast without checking the type?– shmosel
Nov 14 '18 at 0:26
Why does
Employee.equals()
cast without checking the type?– shmosel
Nov 14 '18 at 0:26
add a comment |
3 Answers
3
active
oldest
votes
Here are my notes from reading Effective Java 2nd Edition:
Equals
must adhere to general contract:
- Reflexive: for
non-null x
:x.equals(x) == true
- Symmetric: for
non-null x,y
:x.equals(y) <==> y.equals(x)
- Transitive: for
non-null x,y,z
:x.equals(y) and y.equals(z) ==> x.equals(z) == true
- Consistent: for any non-null x,y: if
x.equals(y) == true
, then for all invocations must return true if no change inx
andy
- Null: for non-null
x
:x.equals(null) == false
High Quality equals method:
- Using == to check if the argument is a reference to this object (
x == x
) - Use instanceof to check if argument is the correct type (also checks for
null
) - Cast the argument to correct type
- For each "significant" field in the class, check if that field of the argument matches the corresponding field of this object
- After done, check if Symmetric, transitive and consistent
Final caveats:
- always override hashCode when you override equals
- Don't try to be too clever
- don't substitute another type for Object in the equals declaration -> Not worth it minor performance gains for added complexity
Hashcode direct quote from Effective Java 2nd Edition
- Store some constant nonzero value, say, 17, in an int variable called result.
For each significant field
f
in your object (each field taken into account by the
equals method, that is), do the following:- Compute an int hash code c for the field:
- If the field is a boolean, compute
(f ? 1 : 0)
. - If the field is a
byte, char, short, or int, compute (int) f.
- If the field is a
long, compute (int) (f ^ (f >>> 32)).
- If the field is a
float, compute Float.floatToIntBits(f).
- If the field is a
double, compute Double.doubleToLongBits(f)
, and
then hash the resultinglong
. - If the field is an object reference and this class’s equals method
compares the field by recursively invokingequals
, recursively
invokehashCode
on the field. If a more complex comparison is
required, compute a “canonical representation” for this field and
invoke hashCode on the canonical representation. If the value of the
field isnull
,return 0
(or some other constant, but 0 is traditional). - If the field is an array, treat it as if each element were a separate field.
That is, compute a hash code for each significant element by applying
these rules recursively, and combine these values per step 2.b. If every
element in an array field is significant, you can use one of the
Arrays.hashCode methods added in release 1.5.
- If the field is a boolean, compute
- Combine the hash code c computed in step 2.a into result as follows:
result = 31 * result + c;
- Compute an int hash code c for the field:
Return result.
- When you are finished writing the hashCode method, ask yourself whether
equal instances have equal hash codes. Write unit tests to verify your intuition!
so following these rules:
@Override
public boolean equals(Object obj)
if (this == obj)
return true;
if (!(obj instanceof Employee))
return false;
Employee other = (Employee) obj;
return super.equals(other) &&
Double.compare(this.salary, other.salary) == 0 &&
this.hireDay.equals(other.hireDay);
In your case though it seems like id
should already uniquely identify any person, so you should just use that for comparison in equals and not override it in any subclass.
add a comment |
Is it possible for two people to ever have the same id
? It shouldn't. So that logic extends to the Employee
class, which means implementing equals
and hashCode
in the Person
class is enough.
At this point, since you're only dealing with an int
, you can use Integer.hashCode(id)
for the hashCode
and just compare the values for the equals
.
1
I understand that implementing a final equals method in the superclass is enough in this specific example, but I'm asking these questions in the general case.
– Mutating Algorithm
Nov 14 '18 at 0:35
add a comment |
If you want to implement equals and hashcode method use eclipse just right click in file go to source and select generate equals() & hashcode() with the fields that you need , just like below :
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53291383%2fwhat-is-the-proper-way-to-implement-a-robust-equals-and-hashcode-method-in-a%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
Here are my notes from reading Effective Java 2nd Edition:
Equals
must adhere to general contract:
- Reflexive: for
non-null x
:x.equals(x) == true
- Symmetric: for
non-null x,y
:x.equals(y) <==> y.equals(x)
- Transitive: for
non-null x,y,z
:x.equals(y) and y.equals(z) ==> x.equals(z) == true
- Consistent: for any non-null x,y: if
x.equals(y) == true
, then for all invocations must return true if no change inx
andy
- Null: for non-null
x
:x.equals(null) == false
High Quality equals method:
- Using == to check if the argument is a reference to this object (
x == x
) - Use instanceof to check if argument is the correct type (also checks for
null
) - Cast the argument to correct type
- For each "significant" field in the class, check if that field of the argument matches the corresponding field of this object
- After done, check if Symmetric, transitive and consistent
Final caveats:
- always override hashCode when you override equals
- Don't try to be too clever
- don't substitute another type for Object in the equals declaration -> Not worth it minor performance gains for added complexity
Hashcode direct quote from Effective Java 2nd Edition
- Store some constant nonzero value, say, 17, in an int variable called result.
For each significant field
f
in your object (each field taken into account by the
equals method, that is), do the following:- Compute an int hash code c for the field:
- If the field is a boolean, compute
(f ? 1 : 0)
. - If the field is a
byte, char, short, or int, compute (int) f.
- If the field is a
long, compute (int) (f ^ (f >>> 32)).
- If the field is a
float, compute Float.floatToIntBits(f).
- If the field is a
double, compute Double.doubleToLongBits(f)
, and
then hash the resultinglong
. - If the field is an object reference and this class’s equals method
compares the field by recursively invokingequals
, recursively
invokehashCode
on the field. If a more complex comparison is
required, compute a “canonical representation” for this field and
invoke hashCode on the canonical representation. If the value of the
field isnull
,return 0
(or some other constant, but 0 is traditional). - If the field is an array, treat it as if each element were a separate field.
That is, compute a hash code for each significant element by applying
these rules recursively, and combine these values per step 2.b. If every
element in an array field is significant, you can use one of the
Arrays.hashCode methods added in release 1.5.
- If the field is a boolean, compute
- Combine the hash code c computed in step 2.a into result as follows:
result = 31 * result + c;
- Compute an int hash code c for the field:
Return result.
- When you are finished writing the hashCode method, ask yourself whether
equal instances have equal hash codes. Write unit tests to verify your intuition!
so following these rules:
@Override
public boolean equals(Object obj)
if (this == obj)
return true;
if (!(obj instanceof Employee))
return false;
Employee other = (Employee) obj;
return super.equals(other) &&
Double.compare(this.salary, other.salary) == 0 &&
this.hireDay.equals(other.hireDay);
In your case though it seems like id
should already uniquely identify any person, so you should just use that for comparison in equals and not override it in any subclass.
add a comment |
Here are my notes from reading Effective Java 2nd Edition:
Equals
must adhere to general contract:
- Reflexive: for
non-null x
:x.equals(x) == true
- Symmetric: for
non-null x,y
:x.equals(y) <==> y.equals(x)
- Transitive: for
non-null x,y,z
:x.equals(y) and y.equals(z) ==> x.equals(z) == true
- Consistent: for any non-null x,y: if
x.equals(y) == true
, then for all invocations must return true if no change inx
andy
- Null: for non-null
x
:x.equals(null) == false
High Quality equals method:
- Using == to check if the argument is a reference to this object (
x == x
) - Use instanceof to check if argument is the correct type (also checks for
null
) - Cast the argument to correct type
- For each "significant" field in the class, check if that field of the argument matches the corresponding field of this object
- After done, check if Symmetric, transitive and consistent
Final caveats:
- always override hashCode when you override equals
- Don't try to be too clever
- don't substitute another type for Object in the equals declaration -> Not worth it minor performance gains for added complexity
Hashcode direct quote from Effective Java 2nd Edition
- Store some constant nonzero value, say, 17, in an int variable called result.
For each significant field
f
in your object (each field taken into account by the
equals method, that is), do the following:- Compute an int hash code c for the field:
- If the field is a boolean, compute
(f ? 1 : 0)
. - If the field is a
byte, char, short, or int, compute (int) f.
- If the field is a
long, compute (int) (f ^ (f >>> 32)).
- If the field is a
float, compute Float.floatToIntBits(f).
- If the field is a
double, compute Double.doubleToLongBits(f)
, and
then hash the resultinglong
. - If the field is an object reference and this class’s equals method
compares the field by recursively invokingequals
, recursively
invokehashCode
on the field. If a more complex comparison is
required, compute a “canonical representation” for this field and
invoke hashCode on the canonical representation. If the value of the
field isnull
,return 0
(or some other constant, but 0 is traditional). - If the field is an array, treat it as if each element were a separate field.
That is, compute a hash code for each significant element by applying
these rules recursively, and combine these values per step 2.b. If every
element in an array field is significant, you can use one of the
Arrays.hashCode methods added in release 1.5.
- If the field is a boolean, compute
- Combine the hash code c computed in step 2.a into result as follows:
result = 31 * result + c;
- Compute an int hash code c for the field:
Return result.
- When you are finished writing the hashCode method, ask yourself whether
equal instances have equal hash codes. Write unit tests to verify your intuition!
so following these rules:
@Override
public boolean equals(Object obj)
if (this == obj)
return true;
if (!(obj instanceof Employee))
return false;
Employee other = (Employee) obj;
return super.equals(other) &&
Double.compare(this.salary, other.salary) == 0 &&
this.hireDay.equals(other.hireDay);
In your case though it seems like id
should already uniquely identify any person, so you should just use that for comparison in equals and not override it in any subclass.
add a comment |
Here are my notes from reading Effective Java 2nd Edition:
Equals
must adhere to general contract:
- Reflexive: for
non-null x
:x.equals(x) == true
- Symmetric: for
non-null x,y
:x.equals(y) <==> y.equals(x)
- Transitive: for
non-null x,y,z
:x.equals(y) and y.equals(z) ==> x.equals(z) == true
- Consistent: for any non-null x,y: if
x.equals(y) == true
, then for all invocations must return true if no change inx
andy
- Null: for non-null
x
:x.equals(null) == false
High Quality equals method:
- Using == to check if the argument is a reference to this object (
x == x
) - Use instanceof to check if argument is the correct type (also checks for
null
) - Cast the argument to correct type
- For each "significant" field in the class, check if that field of the argument matches the corresponding field of this object
- After done, check if Symmetric, transitive and consistent
Final caveats:
- always override hashCode when you override equals
- Don't try to be too clever
- don't substitute another type for Object in the equals declaration -> Not worth it minor performance gains for added complexity
Hashcode direct quote from Effective Java 2nd Edition
- Store some constant nonzero value, say, 17, in an int variable called result.
For each significant field
f
in your object (each field taken into account by the
equals method, that is), do the following:- Compute an int hash code c for the field:
- If the field is a boolean, compute
(f ? 1 : 0)
. - If the field is a
byte, char, short, or int, compute (int) f.
- If the field is a
long, compute (int) (f ^ (f >>> 32)).
- If the field is a
float, compute Float.floatToIntBits(f).
- If the field is a
double, compute Double.doubleToLongBits(f)
, and
then hash the resultinglong
. - If the field is an object reference and this class’s equals method
compares the field by recursively invokingequals
, recursively
invokehashCode
on the field. If a more complex comparison is
required, compute a “canonical representation” for this field and
invoke hashCode on the canonical representation. If the value of the
field isnull
,return 0
(or some other constant, but 0 is traditional). - If the field is an array, treat it as if each element were a separate field.
That is, compute a hash code for each significant element by applying
these rules recursively, and combine these values per step 2.b. If every
element in an array field is significant, you can use one of the
Arrays.hashCode methods added in release 1.5.
- If the field is a boolean, compute
- Combine the hash code c computed in step 2.a into result as follows:
result = 31 * result + c;
- Compute an int hash code c for the field:
Return result.
- When you are finished writing the hashCode method, ask yourself whether
equal instances have equal hash codes. Write unit tests to verify your intuition!
so following these rules:
@Override
public boolean equals(Object obj)
if (this == obj)
return true;
if (!(obj instanceof Employee))
return false;
Employee other = (Employee) obj;
return super.equals(other) &&
Double.compare(this.salary, other.salary) == 0 &&
this.hireDay.equals(other.hireDay);
In your case though it seems like id
should already uniquely identify any person, so you should just use that for comparison in equals and not override it in any subclass.
Here are my notes from reading Effective Java 2nd Edition:
Equals
must adhere to general contract:
- Reflexive: for
non-null x
:x.equals(x) == true
- Symmetric: for
non-null x,y
:x.equals(y) <==> y.equals(x)
- Transitive: for
non-null x,y,z
:x.equals(y) and y.equals(z) ==> x.equals(z) == true
- Consistent: for any non-null x,y: if
x.equals(y) == true
, then for all invocations must return true if no change inx
andy
- Null: for non-null
x
:x.equals(null) == false
High Quality equals method:
- Using == to check if the argument is a reference to this object (
x == x
) - Use instanceof to check if argument is the correct type (also checks for
null
) - Cast the argument to correct type
- For each "significant" field in the class, check if that field of the argument matches the corresponding field of this object
- After done, check if Symmetric, transitive and consistent
Final caveats:
- always override hashCode when you override equals
- Don't try to be too clever
- don't substitute another type for Object in the equals declaration -> Not worth it minor performance gains for added complexity
Hashcode direct quote from Effective Java 2nd Edition
- Store some constant nonzero value, say, 17, in an int variable called result.
For each significant field
f
in your object (each field taken into account by the
equals method, that is), do the following:- Compute an int hash code c for the field:
- If the field is a boolean, compute
(f ? 1 : 0)
. - If the field is a
byte, char, short, or int, compute (int) f.
- If the field is a
long, compute (int) (f ^ (f >>> 32)).
- If the field is a
float, compute Float.floatToIntBits(f).
- If the field is a
double, compute Double.doubleToLongBits(f)
, and
then hash the resultinglong
. - If the field is an object reference and this class’s equals method
compares the field by recursively invokingequals
, recursively
invokehashCode
on the field. If a more complex comparison is
required, compute a “canonical representation” for this field and
invoke hashCode on the canonical representation. If the value of the
field isnull
,return 0
(or some other constant, but 0 is traditional). - If the field is an array, treat it as if each element were a separate field.
That is, compute a hash code for each significant element by applying
these rules recursively, and combine these values per step 2.b. If every
element in an array field is significant, you can use one of the
Arrays.hashCode methods added in release 1.5.
- If the field is a boolean, compute
- Combine the hash code c computed in step 2.a into result as follows:
result = 31 * result + c;
- Compute an int hash code c for the field:
Return result.
- When you are finished writing the hashCode method, ask yourself whether
equal instances have equal hash codes. Write unit tests to verify your intuition!
so following these rules:
@Override
public boolean equals(Object obj)
if (this == obj)
return true;
if (!(obj instanceof Employee))
return false;
Employee other = (Employee) obj;
return super.equals(other) &&
Double.compare(this.salary, other.salary) == 0 &&
this.hireDay.equals(other.hireDay);
In your case though it seems like id
should already uniquely identify any person, so you should just use that for comparison in equals and not override it in any subclass.
edited Nov 14 '18 at 8:38
answered Nov 14 '18 at 1:13
KameeCodingKameeCoding
348520
348520
add a comment |
add a comment |
Is it possible for two people to ever have the same id
? It shouldn't. So that logic extends to the Employee
class, which means implementing equals
and hashCode
in the Person
class is enough.
At this point, since you're only dealing with an int
, you can use Integer.hashCode(id)
for the hashCode
and just compare the values for the equals
.
1
I understand that implementing a final equals method in the superclass is enough in this specific example, but I'm asking these questions in the general case.
– Mutating Algorithm
Nov 14 '18 at 0:35
add a comment |
Is it possible for two people to ever have the same id
? It shouldn't. So that logic extends to the Employee
class, which means implementing equals
and hashCode
in the Person
class is enough.
At this point, since you're only dealing with an int
, you can use Integer.hashCode(id)
for the hashCode
and just compare the values for the equals
.
1
I understand that implementing a final equals method in the superclass is enough in this specific example, but I'm asking these questions in the general case.
– Mutating Algorithm
Nov 14 '18 at 0:35
add a comment |
Is it possible for two people to ever have the same id
? It shouldn't. So that logic extends to the Employee
class, which means implementing equals
and hashCode
in the Person
class is enough.
At this point, since you're only dealing with an int
, you can use Integer.hashCode(id)
for the hashCode
and just compare the values for the equals
.
Is it possible for two people to ever have the same id
? It shouldn't. So that logic extends to the Employee
class, which means implementing equals
and hashCode
in the Person
class is enough.
At this point, since you're only dealing with an int
, you can use Integer.hashCode(id)
for the hashCode
and just compare the values for the equals
.
edited Nov 14 '18 at 0:37
answered Nov 14 '18 at 0:25
LXXIIILXXIII
1,35721330
1,35721330
1
I understand that implementing a final equals method in the superclass is enough in this specific example, but I'm asking these questions in the general case.
– Mutating Algorithm
Nov 14 '18 at 0:35
add a comment |
1
I understand that implementing a final equals method in the superclass is enough in this specific example, but I'm asking these questions in the general case.
– Mutating Algorithm
Nov 14 '18 at 0:35
1
1
I understand that implementing a final equals method in the superclass is enough in this specific example, but I'm asking these questions in the general case.
– Mutating Algorithm
Nov 14 '18 at 0:35
I understand that implementing a final equals method in the superclass is enough in this specific example, but I'm asking these questions in the general case.
– Mutating Algorithm
Nov 14 '18 at 0:35
add a comment |
If you want to implement equals and hashcode method use eclipse just right click in file go to source and select generate equals() & hashcode() with the fields that you need , just like below :
add a comment |
If you want to implement equals and hashcode method use eclipse just right click in file go to source and select generate equals() & hashcode() with the fields that you need , just like below :
add a comment |
If you want to implement equals and hashcode method use eclipse just right click in file go to source and select generate equals() & hashcode() with the fields that you need , just like below :
If you want to implement equals and hashcode method use eclipse just right click in file go to source and select generate equals() & hashcode() with the fields that you need , just like below :
answered Nov 14 '18 at 0:49
user3655403user3655403
614
614
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53291383%2fwhat-is-the-proper-way-to-implement-a-robust-equals-and-hashcode-method-in-a%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
@4castle Well, wouldn't the superclass equals() method take care of that assuming short-circuit evaluation? It would return false before even getting to the cast.
– Mutating Algorithm
Nov 14 '18 at 0:25
Why does
Employee.equals()
cast without checking the type?– shmosel
Nov 14 '18 at 0:26