Implementing hashcode and equals for custom classes

10,860

Solution 1

Equals and hashCode contract in Java:

We must override hashCode() when we override equals() method, equals method in Java must follow its contract with hashCode method in Java as stated below.

  1. If two objects are equal by equals() method then there hashcode must be same.
  2. If two objects are not equal by equals() method then there hashcode could be same or different.

These are sample implementation of equals and hashcode methods for your class:

 //Hashcode Implementation    

   @Override
    public int hashCode() 
    {
        final int prime = 31;
        int result = 1;
        result = prime * result + (isActive ? 1231 : 1237);
        result = prime * result + (wasActive ? 1231 : 1237);
        return result;
    }

//equals Implementation    
    @Override
    public boolean equals(Object obj) 
    {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Cell other = (Cell) obj;
        if (isActive != other.isActive)
            return false;
        if (wasActive != other.wasActive)
            return false;
        return true;
    }

Solution 2

Here is the example of class which has private fields.

public class Test {

    private int num;
    private String data;

    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if ((obj == null) || (obj.getClass() != this.getClass()))
            return false;
        // object must be Test at this point
        Test test = (Test) obj;
        return num == test.num
                && (data == test.data || (data != null && data
                        .equals(test.data)));
    }

    public int hashCode() {
        int hash = 7;
        hash = 31 * hash + num;
        hash = 31 * hash + (null == data ? 0 : data.hashCode());
        return hash;
    }

}

Solution 3

You are SOL. Where hashCode() is used in a key in standard Java collections, it should not change. Or else you need a custom HashSet-like implementation.

Use only non-changing fields (or, if you are daring and don't mind occasional crashes, very rarely changing fields) to calculate hashCode().

(Added). In your particular example, use Object.hashCode().

(Added #2) Even if your Cell class were immutable (the two booleans didn't change) it makes a poor choice for hashing, because it only has 2 bits of range. Imagine hashing all people by whether they are male/female and blue eyes / brown eyes. A very good start, but there's only 4 categories, and there will be like 2 billion people in each one. Ideally, you'd have several other categories, like year of birth, country of birth, etc.

Share:
10,860
letter Q
Author by

letter Q

Updated on June 06, 2022

Comments

  • letter Q
    letter Q almost 2 years

    So I have many custom classes are also have custom clases inside of them using composition.

    My custom classes have variables that change very frequently and I add them to HashSets. So my question is when I implement hashCode - what should I do for a class that only has private fields that constantly change?

    Here is an example of one custom class:

    public class Cell {
        protected boolean isActive;
        protected boolean wasActive;
    
        public Cell() {
        this.isActive = false;
        this.wasActive = false;
        }
    
        // getter and setter methods...
    
        @Override
        public int hashCode() {
        // HOW SHOULD I IMPLEMENT THIS IF THIS custom object is constantly
            // being added into HashSets and have it's private fields isActive
            // and wasActive constantly changed.
        }
    
        // ANOTHER QUESTION Am I missing anything with this below equals implementation?
        @Override
        public boolean equals(Object object) {
        boolean result = false;
        if (object instanceof Cell) {
            Cell otherCell = (Cell) object;
            result = (this.isActive == otherCell.isActive && this.wasActive == 
                otherCell.wasActive);
        }
        return result;
        }
    
  • mattbdean
    mattbdean almost 11 years
    You can't implement hascode using boolean values. You could, but it might not look pretty.
  • Veera
    Veera almost 11 years
    Yes, you are wright. But it is not useful to create hashcode using boolean values.
  • Narendra Pathai
    Narendra Pathai almost 11 years
    How do you suppose this will help? I mean you are using mutable fields in hashcode. Now if the Cell object is used as key in hashed collection and both fields were true while it was entered in HashMap, now the fields change and so does hashcode! If you now try to lookup something based on that object the HashMap will lookup in other bucket and not the original one and you wont find the object.
  • supercat
    supercat almost 11 years
    @NarendraPathai: If a particular instance of an object with a mutable field will never be exposed to code that would mutate that field, is that field of that instance really mutable? Code which stores into hashed collections objects whose hash depends upon mutable fields must ensure that it the objects stored in the collection not be exposed to any code that might cause its hash to change while it's stored in the hashed collection. Oftentimes the easiest way to provide that guarantee is to make the object immutable, but in some cases it may be more practical...
  • supercat
    supercat almost 11 years
    ...to avoid exposing an object instance to anything that doesn't know about the hashed collections in which it is stored, and ensure that any request to change the instance will remove the unchanged instance from the collections, then make the change, and then add the changed instance back into the collections.
  • dodgy_coder
    dodgy_coder about 8 years
    Rather than trying to implement your own hashCode() method, you should use existing standard implementations wherever possible, such as the one for String. To do this, first implement toString() for your object. Then, the equals() method for your object can be built using the toString().equals() and the hashCode() method for your object can just return this.toString().hashCode().