HashSet contains duplicate entries

2019-01-25 08:04发布

A HashSet only stores values ones, when the equals method says that they're the same. Thats what I thought.

But now i'm adding Elements to a HashSet where the equals method returns true and the size of the set still grows?? sorry I'm confused. Some hints where i'm wrong would be nice.

Element t1 = new Element(false, false, false, false);
Element t2 = new Element(true, true, true, true);
Element t3 = new Element(false, false, false, false);

if (t1.equals(t3))
    System.out.println("they're equal");

Set<Element> set = new HashSet<>();

set.add(t1);
set.add(t2);
set.add(t3);

System.out.println("set size: " + set.size());

so in this example my console output is:

they're equal
set size: 3

That makes no sense to me.. shouldn the size be 2?

4条回答
看我几分像从前
2楼-- · 2019-01-25 08:27

If you have your own model classes you need to change some basic functions work like done in the below example.

Execution code :

HashSet<MyModel> models = new HashSet<MyModel>();

for (int i = 1; i < 5; i++)
    models.add(new MyModel(i + "", "Name :" + i + ""));

for (int i = 3; i < 5; i++)
    models.add(new MyModel(i + "", "Name :" + i + ""));

for (Object object : models)
    System.out.println(object);

Model Class :

/**
 * Created by Arun
 */
public static class MyModel {

    private String id = "";
    private String name = "";

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

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return getId();
    }

    @Override
    public boolean equals(Object obj) {
        return !super.equals(obj);
    }

    public int hashCode() {
        return getId().hashCode();
    }

}

Hope this helps.

查看更多
Viruses.
3楼-- · 2019-01-25 08:41

The problem is that your Element class has not overridden the equals and hashCode methods or these implementations are broken.

From Object#equals method javadoc:

The equals method implements an equivalence relation on non-null object references:

  • It is reflexive: for any non-null reference value x, x.equals(x) should return true.
  • It is symmetric: for any non-null reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true.
  • It is transitive: for any non-null reference values x, y, and z, if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true. It is consistent: for any non-null reference values x and y, multiple invocations of -x.equals(y) consistently return true or consistently return false, provided no information used in equals comparisons on the objects is modified.
  • For any non-null reference value x, x.equals(null) should return false.

From Object#hashCode method javadoc:

The general contract of hashCode is:

  • Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.
  • If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
  • It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hash tables.

Make sure the implementations of these methods satisfy these rules and your Set (backed by a HashSet) will work as expected.

查看更多
手持菜刀,她持情操
4楼-- · 2019-01-25 08:44

Yes We Can implement it with the object of the classes which are not FINAL.

HashSet Checks for two methods hashCode() and equals() before adding any Object. First it checks for the method hashCode(),if it returns the hashcode which is same with any of the object in Set, then it checks for the equals method for that object,which internally compares the references for both objects i.e this.obj1==obj.If these are the same references in that case it returns true means it is a duplicate value. We can add duplicate non-final objects by overriding HashCode and equals method. In HashCode() you can return same hashcode in case of same parameters.

See example:

public class Product {
int i;
Product(int a)
{
    this.i=a;
}
@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + i;
    return result;
}
@Override
public boolean equals(Object obj) {
    /*if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    Product other = (Product) obj;
    if (i != other.i)
        return false;
    return true;*/
    return true;
}
}
`

`
import java.util.HashSet;
import java.util.Set;
public class Main {
public static void main(String[] args) {
    Product p1=new Product(1);
    Product p2=new Product(1);
    Product p3=new Product(1);
    Set s=new HashSet();
    s.add(p1);
    s.add(p2);
    s.add(p3);
    System.out.println(s.size());
}
}

The output will be 1.

P.S:Without overriding these methods,output will be 3 since it will use their default behavior.

查看更多
来,给爷笑一个
5楼-- · 2019-01-25 08:51

Your objects have different hashes so HashSet "puts" then in different "buckets".

查看更多
登录 后发表回答