我正在尝试找到关于如何使用自定义对象作为HashMap的键或作为存储在HashSet中的对象的权威文档。
通过阅读各种帖子,我发现你应该在自定义对象中覆盖两个方法equals()和hashCode()(例如Overriding equals and hashCode in Java)。
但是,当我阅读HashSet和HashMap的Oracle / Sun官方Javadoc时,他们根本没有提到覆盖这些方法。这些说明是否埋在文档中的其他位置?如果是这样,我在哪里可以找到它们?
答案 0 :(得分:3)
您需要来覆盖equals
和hashCode
,但您确实需要一致 equals
和{ {1}}方法。
也就是说,如果hashCode
,则必须是obj.equals(obj2)
的情况。为了获得良好的性能,反向(非obj.hashCode() == obj2.hashCode()
对象具有不等equals()
值)应尽可能正常,但这不是必需的,如果您的对象具有多个,则不能始终满足2 ^ 32个州)。
默认的hashCode()
和equals()
方法遵循这一点并具有标识语义 - 如果对象实际上是同一个对象(obj == obj2),则它们是相等的。
如果您想要值语义 - 例如,具有相同状态的两个对象相等,则应覆盖这些方法。
答案 1 :(得分:0)
Collections API根据equals()和hashCode()描述合同。如果您希望键的多个实例彼此相等,则需要按照Object类指定的契约覆盖equals()和hashCode()。
Set interface描述了合同:
更正式地说,集合不包含任何元素对e1和e2 e1.equals(e2),最多一个null元素。正如其名称所暗示的那样, 这个界面模拟了数学集抽象。
equals()和hashCode()的契约由Object类指定。
在“有效的Java”中,Joshua Bloch建议您在覆盖hashCode
时始终覆盖equals
,以避免违反这些合同。
答案 2 :(得分:0)
在java.lang.Object的合同中详细讨论了这个问题。
答案 3 :(得分:0)
在Set
和Map
的文档中,它们是它们实现的接口。
要求不是任意的,它是保证接口方法按预期工作的唯一方法 - 通过能够判断哪些可能是不同Java对象的键应该被真正地视为相同的键而不是 - 例如,"abc"
和"ab" + "c"
是不同的对象,但equals
的实现确保它们被视为相同的密钥。至于hashCode
,需要在作为这些接口基础的数据结构中找到有意义的位置。
答案 4 :(得分:0)
据我所知,密钥必须是一个不可变对象。
如果它是可变的,那么在将其添加到地图后,它的哈希码可能会发生变化。 然后地图可能会遇到问题
Setting own class as key in java Hashmap
以下示例说明了这一点:
import java.util.HashMap;
class Test{
public int i=0;
@Override
public int hashCode() {
return i;
}
}
public class Main {
public static void main(String[] args) {
HashMap<Test, String> hm = new HashMap<>();
Test t1 = new Test();
hm.put(t1, "found");
System.out.println(hm.get(t1));
t1.i=2;
System.out.println(hm.get(t1));
}
}
/*
output:
found
null
*/