Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing hashcode and equals for custom classes

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;
    }
like image 977
Wang-Zhao-Liu Q Avatar asked Jul 23 '13 04:07

Wang-Zhao-Liu Q


2 Answers

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;
    }
like image 106
Ankur Lathi Avatar answered Oct 13 '22 02:10

Ankur Lathi


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.

like image 22
user949300 Avatar answered Oct 13 '22 01:10

user949300