了解HashSet

时间:2014-05-09 11:45:59

标签: java set hashset

这是我的问题,可以" HashSet Objects"有重复的元素??

如果我读了Set Interface定义,我看到:

  

不包含重复元素的集合。更正式地说,集合不包含元素对e1和e2,使得e1.equals(e2)和至多一个null元素。正如其名称所暗示的,该界面模拟数学集抽象。

现在我们要写一个简单的例子:

定义A类:

public class A {

    @Override
    public boolean equals(Object obj) {
        return true;
    }

}

现在执行此代码;

Set<A> set = new HashSet<A>();
set.add(new A());
set.add(new A());
System.out.println(set.toString());

这就是结果:

  

[com.maths.graphs.A@b9e9a3,com.maths.graphs.A@18806f7]

为什么实现像HashSet这样的Set Interface的类包含重复的元素?

谢谢!

2 个答案:

答案 0 :(得分:2)

你破坏了equals-hashcode合约。

如果您覆盖equals方法,则还必须覆盖hashCode()方法,以便:

  

两个相等的对象给出相同的散列,并且最好是不相等的   对象极有可能提供不同的哈希码

这很重要,因为许多对象(不出所料地包括HashSet)使用哈希码作为消除不等对象的快速,有效的早期步骤。这就是这里发生的事情,因为不同的A的哈希码将会有所不同,因为他们仍在使用.hashCode()中提供的object的实现。

如果要按如下方式创建A类,则在集合

中不允许超过1 A.
public class A {

    @Override
    public boolean equals(Object obj) {
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 1; //any number since in this case all objects of class A are equal to everything
        return hash;
    }

}

来自javadoc

  

public int hashCode()

     

返回对象的哈希码值。支持此方法   散列表的好处,例如HashMap提供的散列表。

     

hashCode的一般合约是:

     
      
  • 每当在执行Java应用程序期间多次在同一对象上调用它时,hashCode方法必须始终如一   返回相同的整数,前提是equals中没有使用的信息   对象的比较被修改。不需要保留该整数   从一个应用程序的执行到另一个执行的一致性   相同的申请。

  •   
  • 如果两个对象根据equals(Object)方法相等,则必须对两个对象中的每一个调用hashCode方法   产生相同的整数结果。

  •   
  • 如果两个对象根据equals(java.lang.Object)方法不相等,则不需要调用hashCode方法   两个对象中的每一个都必须产生不同的整数结果。   但是,程序员应该意识到产生了不同的   不等对象的整数结果可以提高性能   哈希表。

  •   

如果在覆盖equals方法时不包含重写HashCode方法并且可以为您生成hashCode方法,则大多数IDE都会反对。

注释

严格来说,我的hashCode()方法并不完全满足合同。由于A#equals(Object obj)等于任何,包括不属于A类的对象,因此无法完全满足合同。理想情况下,equals方法也将更改为以下内容以涵盖所有基础

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof A){
           return true;
        }else{
           return false;
        }
    }

答案 1 :(得分:0)

这里HashSet没有重复项,因为两个add方法在HashSet中添加了新对象,这些是不同的对象。由于这个原因,集合的两个元素的哈希码不同的原因。尝试将代码更改为:

Set<A> set = new HashSet<A>();
A a = new A();
set.add(a);
set.add(a);
System.out.println(set.toString());

你会发现集合中只有一个值。

或者只是在代码中添加以下内容并检查

@Override
public int hashCode() {
    return 31;
}