嗨,我是java的新手,因为我知道set collection不会重复,当contains已经存在于collection中时,它的contains方法应该返回true。我试图在程序下运行,但我得到了意想不到的结果。
public class UserDefinedName {
private final String first, last;
public UserDefinedName(String first, String last) {
this.first = first;
this.last = last;
}
public boolean equals(Object o) {
if (!(o instanceof UserDefinedName))
return false;
UserDefinedName n = (UserDefinedName) o;
return n.first.equals(first) && n.last.equals(last);
}
public static void main(String[] args) {
Set<UserDefinedName> s = new HashSet<UserDefinedName>();
s.add(new UserDefinedName("Carballo", "Videl"));
System.out.println(s.contains(new UserDefinedName("Carballo", "Videl")));
}
}
我期待输出 true ,但程序打印 false 。 我做错了什么?
答案 0 :(得分:8)
表单java doc
如果两个对象根据equals(Object)方法相等,那么 必须在两个对象中的每一个上调用hashCode方法 相同的整数结果。
如果hashCode()方法没有覆盖,则使用Object的hashCode()方法,这是默认实现。
在你的情况下,你有覆盖equals方法,但你使用hashCode()的默认实现,因为你没有覆盖UserDefinedName类中的hashCode()方法。
UserDefinedName类重写equals方法和 hashCode契约要求相等的对象具有相同的哈希码。至 履行此合同,您必须随时覆盖hashCode 覆盖等于
添加以下代码,它将起作用。
public int hashCode() {
return 37 * first.hashCode() + last.hashCode();
}
答案 1 :(得分:1)
因为hashSet
使用对象的哈希码值来存储它。因此,它要求您必须覆盖您自己的类中的方法hashCode。由于您没有覆盖它,因此它使用从对象类继承的hashCode方法。
来自对象类的哈希码是使用对象的内存地址计算的,即:
UserDefinedName p = new UserDefinedName("Carballo", "Videl");
System.out.println(p);
System.out.println(0x1e5e2c3);
System.out.println(p.hashCode());
输出:
UserDefinedName@1e5e2c3
31843011
31843011
所以如果你试过这个,你会看到它输出为true:
Set<UserDefinedName> s = new HashSet<UserDefinedName>();
UserDefinedName p = new UserDefinedName("Carballo", "Videl");
s.add(p);
System.out.println(s.contains(p));
现在,如果你想比较你的用户类correclty,你将不得不覆盖你的hashCode
方法(你可以用eclipse生成它)来按字段生成hashCode
你的对象。
如果您的班级使用此方法,则会为您提供的代码打印true。
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((first == null) ? 0 : first.hashCode());
result = prime * result + ((last == null) ? 0 : last.hashCode());
return result;
}
答案 2 :(得分:1)
当你重写equals方法时,也总是覆盖hashcode方法。 一个简单的规则是,如果两个对象被认为是相等的,那么它们应该返回相同的哈希码。
我接受了你的代码并在eclipse的帮助下生成了equals和hashcode
import java.util.HashSet;
import java.util.Set;
public class UserDefinedName {
private final String first, last;
public UserDefinedName(String first, String last) {
this.first = first;
this.last = last;
}
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((first == null) ? 0 : first.hashCode());
result = prime * result + ((last == null) ? 0 : last.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
UserDefinedName other = (UserDefinedName) obj;
if (first == null) {
if (other.first != null)
return false;
} else if (!first.equals(other.first))
return false;
if (last == null) {
if (other.last != null)
return false;
} else if (!last.equals(other.last))
return false;
return true;
}
public static void main(String[] args) {
Set<UserDefinedName> s = new HashSet<UserDefinedName>();
s.add(new UserDefinedName("Carballo", "Videl"));
System.out.println(s.contains(new UserDefinedName("Carballo", "Videl")));
UserDefinedName obj1 = new UserDefinedName("prasad", "kharkar");
UserDefinedName obj2 = new UserDefinedName("prasad", "kharkar");
System.out.println(obj1.equals(obj2));
System.out.println(obj1.hashCode());
System.out.println(obj2.hashCode());
}
}
输出
true
true
-1072813416
-1072813416
答案 3 :(得分:0)
除了equals之外,还需要实现hashcode()方法。
HashSet是一种在内部使用HashMap的数据结构。在HashMap中,对象存储在键值对中。但是,HashSet只接受键,相应的值是一个空的虚拟对象(这是由JVM负责的)。现在,要使此散列机制正常工作,您需要实现equals()以及hashCode()方法。根据{{3}}:
此类实现Set接口,由哈希表支持 (实际上是一个HashMap实例)。它不能保证 集合的迭代顺序;特别是,它并不保证 订单将随着时间的推移保持不变。该类允许null 元件。
此类为基本操作提供恒定的时间性能 (添加,删除,包含和大小),假设散列函数分散 桶中的元素正确。迭代这个集合 需要的时间与HashSet实例的大小之和成正比 (元素数量)加上后备HashMap的“容量” 实例(桶数)。
您可能想查看JDK documentation - 第二版 - 第三章 - 所有对象共有的方法“。这将使您清楚地了解实现equals()和hashCode()方法的最佳实践。 / p>
答案 4 :(得分:0)
HashSet
需要覆盖hashCode
和equals
方法。