Java HashSet包含重复的条目

Java HashSet包含重复的条目,java,set,unique,hashset,Java,Set,Unique,Hashset,当equals方法表示值相同时,HashSet只存储值1。我就是这么想的 但是现在我正在向HashSet添加元素,其中equals方法返回true,并且集合的大小仍在增长??对不起,我弄糊涂了。一些我错的地方的提示会很好 Element t1 = new Element(false, false, false, false); Element t2 = new Element(true, true, true, true); Element t3 = new Element(false, fal

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

但是现在我正在向HashSet添加元素,其中equals方法返回true,并且集合的大小仍在增长??对不起,我弄糊涂了。一些我错的地方的提示会很好

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());
Element t1=新元素(false,false,false,false);
元素t2=新元素(真,真,真,真);
元素t3=新元素(假,假,假,假);
如果(t1等于(t3))
System.out.println(“它们是相等的”);
Set=newhashset();
增加(t1);
增加(t2);
增加(t3);
System.out.println(“设置大小:+set.size());
因此,在本例中,我的控制台输出为:

他们是平等的
套装尺寸:3件


那对我来说毫无意义。。大小是否应该为2?

问题在于
元素
类没有覆盖
equals
hashCode
方法,或者这些实现被破坏

从方法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
从方法javadoc:

hashCode的总合同为:

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

确保这些方法的实现满足这些规则,并且您的
集(由
HashSet
支持)将按预期工作。

您的对象具有不同的散列,因此HashSet“放置”在不同的“bucket”中。

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

在添加任何对象之前,HashSet检查两个方法
hashCode()
equals()
。 首先,它检查方法
hashCode()
,如果它返回的hashCode与集合中的任何对象相同,则检查该对象的equals方法,它在内部比较两个对象的引用,即
this.obj1==obj
。如果在这种情况下这些引用相同,则返回true表示该值重复。 我们可以通过重写HashCode和equals方法来添加重复的非final对象。 在HashCode()中,如果参数相同,则可以返回相同的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


注意:在不重写这些方法的情况下,输出将是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();
    }

}

希望这能有所帮助。

有点输入错误。我没有选择t2.equals(t3),而是选择了t1.equals(t3),它说t1和t3根据它们的equals方法是相等的阅读我的答案,你还需要重写
hashCode
方法。我的元素有一个equals方法,它检查4个布尔值,如果它们相同,它返回true。我得到的输出(“它们是相等的”)表明,相等的方法应该有效/equals确实已经实现。@tobi
Set
使用
equals
hashCode
方法。您的
元素
类也必须重写
hashCode
方法,以使
集合
按预期工作。如果这没有反映在我的答案中,请刷新页面。好的,这可能就是答案。。我试试看,谢谢。但是我对hashCode方法的需要有点困惑,因为sets add方法的doc说:更正式地说,如果这个集合不包含元素e2,那么将指定的元素e添加到这个集合中(e==null?e2==null:e.equals(e2))。(与hashCode无关)@tobi除非您重写
hashCode()
以及
equals()
,否则您违反了这些方法的约定。仅仅因为
HashSet#add()
的Javadoc没有引用
hashCode()
并不意味着可以忽略
equals()
hashCode()
contracts。当然给出了解决方案。我只是告诉了逻辑,在添加到集合中之前如何比较元素。因此,必须重写这两种方法才能创建重复条目。如果它们的hashcode()返回的值不同,那么就没有必要重写equals()。我注意到duplicate对象的hashcode与您所说的相同。但如何解决多回路的问题呢?