4

I am trying to create custom objects for HashMap and have written code for hashcode and equals method. While adding objects in HashMap, equals method is true and hashcode is returning same value for both objects yet HashMap is adding both objects as different objects. How can this be possible? Below is my code:

class B {
    String name;
    int id;

    public B(String name, int id)
    {
        this.name=name;
        this.id=id;
    }

    public boolean equals(B b){
        if(this==b)
            return true;
        if(b==null)
            return false;
        if(this.name.equals(b.name) && this.id==b.id)
            return true;
        else
            return false;
    }

    public int hashcode(){
        return this.id;
    }

    public String toString(){
        return "name: "+name+" id: "+id;
    }
}

For testing above code, I have added following in my main class:

HashMap<B,String> sample=new HashMap<>();
B b1 = new B("Volga",1);
B b2 = new B("Volga",1);
System.out.println(b1.equals(b2));
System.out.println(b1.hashcode()+"    "+b2.hashcode());
sample.put(b1, "wrog");
sample.put(b2,"wrog");
System.out.println(sample);

This is producing following output:

true
1    1
{name: Volga id: 1=wrog, name: Volga id: 1=wrog}

Can someone please explain why is this happening?

thokuest
  • 5,800
  • 24
  • 36
volga dr
  • 41
  • 1
  • 8
    Your equals method does not override the one from Object. It should take Object as argument, not B. – maba Aug 17 '18 at 07:09
  • 4
    **always** add the `@Override`annotation to a method which is supposed to override or implement a method. Not only that doecuments it, but if you make the mistake you just made, the compiler will refuse to compile. – JB Nizet Aug 17 '18 at 07:10
  • 3
    Also there's typo in `hashcode`. It should be `hashCode` with capital `C`... – Shanu Gupta Aug 17 '18 at 07:13
  • Thanks, I missed that and it was the issue. its working fine now!!! – volga dr Aug 17 '18 at 07:14

3 Answers3

7

You've got two issues here:

  1. Instead of implementing equals(B) you should have implemented equals(Object) (Javadoc)
  2. It needs to be hashCode() instead of hashcode() (Javadoc)

A working implementation might look like this:

class B {
    String name;
    int id;

    public B(String name, int id) {
        this.name = name;
        this.id = id;
    }

    @Override
    public int hashCode() {
        return this.id;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        B other = (B) obj;
        if (id != other.id) {
            return false;
        }
        if (name == null) {
            if (other.name != null) {
                return false;
            }
        } else if (!name.equals(other.name)) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "name: " + name + " id: " + id;
    }
}

As a general advise, make sure to specify the @Override annotation. Your IDE and the Java compiler (javac) can then help you spot these kind of issues.

thokuest
  • 5,800
  • 24
  • 36
  • 1
    "if you're working in an IDE, like Eclipse, IntelliJ IDEA, Netbeans and the like, make sure to specify the @Override annotation." The check is not related to IDE features. `@Override` will produce a compilation error. So just javac is enough to detect that. – davidxxx Aug 17 '18 at 07:23
3

Actually you are neither overriding the hashCode, nor the equals method of java.lang.Object, due to a typo (hashcode is what you used) and usage of a wrong parameter in the equals method.

An actual implementation which works for both would be:

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    B b = (B) o;
    return id == b.id &&
            Objects.equals(name, b.name);
}

@Override
public int hashCode() {
    return Objects.hash(name, id);
}

This implementation was actually generated by IntelliJ IDEA. What I actually like about this implementation is that it uses the java.util.Objects.hash() method which simplifies the generation of hashCode a lot and was introduced in Java 7.

gil.fernandes
  • 12,978
  • 5
  • 63
  • 76
1

You have to override the equals(Object) & hashCode() methods instead of equals(B b) & hashcode().

Try to implement the methods with following signature & it should work:

@Override
public boolean equals(Object o){...}

@Override
public int hashCode() {...}

You could also use your IDE's autogenerate feature to generate these methods. That way, there are no chances of error.

Pankaj Singhal
  • 15,283
  • 9
  • 47
  • 86