HashSet包含重复的条目

时间:2013-04-26 13:51:32

标签: java set unique hashset

当equals方法表明它们是相同的时,HashSet只存储值1。这就是我的想法。

但是现在我正在向HashSet添加Elements,其中equals方法返回true并且set的大小仍在增长?对不起,我很困惑。我错了一些提示会很好。

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());

所以在这个例子中我的控制台输出是:

  他们是平等的   设定大小:3

这对我来说没有意义..大小应该是2吗?

4 个答案:

答案 0 :(得分:19)

问题是,您的Element类没有覆盖equalshashCode方法,或者这些实现已被破坏。

来自Object#equals方法javadoc:

  

equals方法在非null对象引用上实现等价关系:

     
      
  • 它是自反的:对于任何非空引用值x,x.equals(x)应该返回true。
  •   
  • 它是对称的:对于任何非空引用值x和y,当且仅当y.equals(x)返回true时,x.equals(y)才应返回true。
  •   
  • 它是传递性的:对于任何非空引用值x,y和z,如果x.equals(y)返回true而y.equals(z)返回true,则x.equals(z)应返回true 。   它是一致的:对于任何非空引用值x和y,-x.equals(y)的多次调用始终返回true或始终返回false,前提是没有修改对象的equals比较中使用的信息。
  •   
  • 对于任何非空引用值x,x.equals(null)应返回false。
  •   

来自Object#hashCode方法javadoc:

  

hashCode的一般合约是:

     
      
  • 每当在执行Java应用程序期间多次在同一对象上调用它时,hashCode方法必须始终返回相同的整数,前提是不修改对象的equals比较中使用的信息。从应用程序的一次执行到同一应用程序的另一次执行,此整数不需要保持一致。
  •   
  • 如果两个对象根据equals(Object)方法相等,则对两个对象中的每一个调用hashCode方法必须生成相同的整数结果。
  •   
  • 如果两个对象根据equals(java.lang.Object)方法不相等,则不需要在两个对象中的每一个上调用hashCode方法必须生成不同的整数结果。但是,程序员应该知道为不等对象生成不同的整数结果可能会提高哈希表的性能。
  •   

确保这些方法的实现符合这些规则,Set(由HashSet支持)将按预期工作。

答案 1 :(得分:4)

你的对象有不同的哈希值,所以HashSet“put”然后在不同的“桶”中。

答案 2 :(得分:3)

如果您有自己的模型类,则需要更改一些基本功能,如下例所示。

执行代码:

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);

模特课程:

/**
 * 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();
    }

}

希望这有帮助。

答案 3 :(得分:1)

是的我们可以使用不是 FINAL 的类的对象来实现它。

HashSet在添加任何Object之前检查两个方法hashCode()equals()。 首先,它检查方法hashCode(),如果它返回与相同的哈希码与Set中的任何对象,则它检查该对象的equals方法,该方法在内部比较两个对象的引用,即this.obj1==obj。如果这些是相同的引用,则返回 true 表示它是重复值。 我们可以通过重写HashCode和equals方法来添加重复的非final对象。 在HashCode()中,如果参数相同,则可以返回相同的哈希码。

参见示例:

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());
}
}

输出为1。

P.S:如果没有覆盖这些方法,输出将为3,因为它将使用它们的默认行为。