What is the proper way to implement a robust equals() and hashCode() method in an inheritance hierarchy?










1















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?










share|improve this question
























  • @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















1















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?










share|improve this question
























  • @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













1












1








1








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?










share|improve this question
















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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 does Employee.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











  • Why does Employee.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












3 Answers
3






active

oldest

votes


















1














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 in x and y

  • Null: for non-null x: x.equals(null) == false

High Quality equals method:



  1. Using == to check if the argument is a reference to this object (x == x)

  2. Use instanceof to check if argument is the correct type (also checks for null)

  3. Cast the argument to correct type

  4. For each "significant" field in the class, check if that field of the argument matches the corresponding field of this object

  5. 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



  1. Store some constant nonzero value, say, 17, in an int variable called result.


  2. 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:

      1. If the field is a boolean, compute (f ? 1 : 0).

      2. If the field is a byte, char, short, or int, compute (int) f.

      3. If the field is a long, compute (int) (f ^ (f >>> 32)).

      4. If the field is a float, compute Float.floatToIntBits(f).

      5. If the field is a double, compute Double.doubleToLongBits(f), and
        then hash the resulting long.

      6. If the field is an object reference and this class’s equals method
        compares the field by recursively invoking equals, recursively
        invoke hashCode 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 is null, return 0 (or some other constant, but 0 is traditional).

      7. 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.


    • Combine the hash code c computed in step 2.a into result as follows:
      result = 31 * result + c;


  3. Return result.


  4. 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.






share|improve this answer
































    1














    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.






    share|improve this answer




















    • 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














    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 :



    enter image description here



    enter image description here






    share|improve this answer






















      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
      );



      );













      draft saved

      draft discarded


















      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









      1














      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 in x and y

      • Null: for non-null x: x.equals(null) == false

      High Quality equals method:



      1. Using == to check if the argument is a reference to this object (x == x)

      2. Use instanceof to check if argument is the correct type (also checks for null)

      3. Cast the argument to correct type

      4. For each "significant" field in the class, check if that field of the argument matches the corresponding field of this object

      5. 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



      1. Store some constant nonzero value, say, 17, in an int variable called result.


      2. 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:

          1. If the field is a boolean, compute (f ? 1 : 0).

          2. If the field is a byte, char, short, or int, compute (int) f.

          3. If the field is a long, compute (int) (f ^ (f >>> 32)).

          4. If the field is a float, compute Float.floatToIntBits(f).

          5. If the field is a double, compute Double.doubleToLongBits(f), and
            then hash the resulting long.

          6. If the field is an object reference and this class’s equals method
            compares the field by recursively invoking equals, recursively
            invoke hashCode 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 is null, return 0 (or some other constant, but 0 is traditional).

          7. 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.


        • Combine the hash code c computed in step 2.a into result as follows:
          result = 31 * result + c;


      3. Return result.


      4. 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.






      share|improve this answer





























        1














        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 in x and y

        • Null: for non-null x: x.equals(null) == false

        High Quality equals method:



        1. Using == to check if the argument is a reference to this object (x == x)

        2. Use instanceof to check if argument is the correct type (also checks for null)

        3. Cast the argument to correct type

        4. For each "significant" field in the class, check if that field of the argument matches the corresponding field of this object

        5. 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



        1. Store some constant nonzero value, say, 17, in an int variable called result.


        2. 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:

            1. If the field is a boolean, compute (f ? 1 : 0).

            2. If the field is a byte, char, short, or int, compute (int) f.

            3. If the field is a long, compute (int) (f ^ (f >>> 32)).

            4. If the field is a float, compute Float.floatToIntBits(f).

            5. If the field is a double, compute Double.doubleToLongBits(f), and
              then hash the resulting long.

            6. If the field is an object reference and this class’s equals method
              compares the field by recursively invoking equals, recursively
              invoke hashCode 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 is null, return 0 (or some other constant, but 0 is traditional).

            7. 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.


          • Combine the hash code c computed in step 2.a into result as follows:
            result = 31 * result + c;


        3. Return result.


        4. 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.






        share|improve this answer



























          1












          1








          1







          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 in x and y

          • Null: for non-null x: x.equals(null) == false

          High Quality equals method:



          1. Using == to check if the argument is a reference to this object (x == x)

          2. Use instanceof to check if argument is the correct type (also checks for null)

          3. Cast the argument to correct type

          4. For each "significant" field in the class, check if that field of the argument matches the corresponding field of this object

          5. 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



          1. Store some constant nonzero value, say, 17, in an int variable called result.


          2. 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:

              1. If the field is a boolean, compute (f ? 1 : 0).

              2. If the field is a byte, char, short, or int, compute (int) f.

              3. If the field is a long, compute (int) (f ^ (f >>> 32)).

              4. If the field is a float, compute Float.floatToIntBits(f).

              5. If the field is a double, compute Double.doubleToLongBits(f), and
                then hash the resulting long.

              6. If the field is an object reference and this class’s equals method
                compares the field by recursively invoking equals, recursively
                invoke hashCode 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 is null, return 0 (or some other constant, but 0 is traditional).

              7. 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.


            • Combine the hash code c computed in step 2.a into result as follows:
              result = 31 * result + c;


          3. Return result.


          4. 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.






          share|improve this answer















          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 in x and y

          • Null: for non-null x: x.equals(null) == false

          High Quality equals method:



          1. Using == to check if the argument is a reference to this object (x == x)

          2. Use instanceof to check if argument is the correct type (also checks for null)

          3. Cast the argument to correct type

          4. For each "significant" field in the class, check if that field of the argument matches the corresponding field of this object

          5. 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



          1. Store some constant nonzero value, say, 17, in an int variable called result.


          2. 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:

              1. If the field is a boolean, compute (f ? 1 : 0).

              2. If the field is a byte, char, short, or int, compute (int) f.

              3. If the field is a long, compute (int) (f ^ (f >>> 32)).

              4. If the field is a float, compute Float.floatToIntBits(f).

              5. If the field is a double, compute Double.doubleToLongBits(f), and
                then hash the resulting long.

              6. If the field is an object reference and this class’s equals method
                compares the field by recursively invoking equals, recursively
                invoke hashCode 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 is null, return 0 (or some other constant, but 0 is traditional).

              7. 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.


            • Combine the hash code c computed in step 2.a into result as follows:
              result = 31 * result + c;


          3. Return result.


          4. 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.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Nov 14 '18 at 8:38

























          answered Nov 14 '18 at 1:13









          KameeCodingKameeCoding

          348520




          348520























              1














              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.






              share|improve this answer




















              • 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














              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.






              share|improve this answer




















              • 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








              1







              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.






              share|improve this answer















              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.







              share|improve this answer














              share|improve this answer



              share|improve this answer








              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












              • 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











              1














              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 :



              enter image description here



              enter image description here






              share|improve this answer



























                1














                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 :



                enter image description here



                enter image description here






                share|improve this answer

























                  1












                  1








                  1







                  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 :



                  enter image description here



                  enter image description here






                  share|improve this answer













                  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 :



                  enter image description here



                  enter image description here







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Nov 14 '18 at 0:49









                  user3655403user3655403

                  614




                  614



























                      draft saved

                      draft discarded
















































                      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.




                      draft saved


                      draft discarded














                      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





















































                      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







                      這個網誌中的熱門文章

                      Barbados

                      How to read a connectionString WITH PROVIDER in .NET Core?

                      Node.js Script on GitHub Pages or Amazon S3