简体   繁体   中英

Why is my HashSet storing 2 identical objects with the same hashCode?

I'm doing a school assignment where I need to store a bunch of contacts. Each contact has a HashSet of social network accounts, addresses and phone numbers.

I DO NOT want to store multiple copies of the same object in my HashSet , so I have overridden the hashCode() and equals() method for each object.

But for my social network account object only,my HashSet is storing the same object twice! I have two different objects:

SocialNetworkAccount s1 = new SocialNetworkAccount(SocialNetworkAccount.AccountType.FACEBOOK, "wallcrawler123");

SocialNetworkAccount s2 = new SocialNetworkAccount(SocialNetworkAccount.AccountType.FACEBOOK, "wallcrawler123");

s1.equals(s2) returns true and s1.hashCode() == s2.hashCode() returns true , but s1 == s2 returns false ! Why?

This is the hashCode() method I'm using:

public int hashCode() {
    int prime = 31;
    int result = 1;
    result = result*prime + type.hashCode();
    result = result*prime + id.hashCode();
    return result;
}

The == operator compares references. Since there are two different objects, their references will be different.

SocialNetworkAccount s1 = new SocialNetworkAccount(SocialNetworkAccount.AccountType.FACEBOOK, "wallcrawler123");

SocialNetworkAccount s2 = s1;

if (s1 == s2) { 
    System.out.println("The references are the same."); 
}

I suspect that the problem is that your equals method is not overriding Object 's equals method , which takes an Object as a parameter.

I suspect that your equals method takes a parameter of SocialNetworkAccount , not Object . I can't know for sure because you haven't posted your equals method, but it is a possible explanation. In this case, the equals method in Object is not overridden, so when HashSet (eventually) calls it, it calls Object 's equals method, which compares references to see if they are the same.

If so, modify your equals method to accept an Object instead of a SocialNetworkAccount , so it overrides equals properly.

Also, using the @Override annotation will catch when a method that intends to override another method in fact does not override it.

hashCode method is used to coarsly assign entries to the table, but the equals(...) method has to return true for the two instances to be treated as identical.

Since you don't show us the equals method I assume you have not created your own version, which means the HashTable is useing the default implementation, which does a == b and your two instances are not the same instance, so that returns false, hence two entries in the table.

What you need to do is implement the equals method too:

public boolean equals(Object o) {
    if (o == this) {
        return true;
    }
    if (o instanceof SocialNetworkAccount) {
        SocialNetworkAccount their = (SocialNetworkAccount)o;
        return xxx.equals(their.xxx ) &&  yyy.equals(their.yyy) && ...;
    }
    return false;
}

Replace xxx and yyy and so on with the values in your class.

See the hashCode and equals contract

maybe you have done somthing like this?

SocialNetworkAccount s1 = new SocialNetworkAccount(SocialNetworkAccount.AccountType.FACEBOOK, "foo");
SocialNetworkAccount s2 = new SocialNetworkAccount(SocialNetworkAccount.AccountType.FACEBOOK, "bar");

hashSet.add(s1);
hashSet.add(s2);

s2.setNickname("foo");

System.out.println(s1.equals(s2));  // true
System.out.println(hashSet);        // [FACEBOOK:foo, FACEBOOK:foo]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM