这是我的问题,可以" 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的类包含重复的元素?
谢谢!
答案 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;
}