我正在尝试找到有关如何使用自定义对象作为 HashMap 的键或存储在 HashSet 中的对象的权威文档。
通过阅读各种帖子,我以某种方式发现您应该覆盖自定义对象中的两个方法 equals() 和 hashCode() (例如覆盖 Java 中的 equals 和 hashCode)。
但是,当我阅读HashSet和HashMap的 Oracle/Sun 官方 Javadocs 时,他们根本没有提到重写这些方法。这些说明是否隐藏在文档的其他地方?如果是这样,我在哪里可以找到它们?
我正在尝试找到有关如何使用自定义对象作为 HashMap 的键或存储在 HashSet 中的对象的权威文档。
通过阅读各种帖子,我以某种方式发现您应该覆盖自定义对象中的两个方法 equals() 和 hashCode() (例如覆盖 Java 中的 equals 和 hashCode)。
但是,当我阅读HashSet和HashMap的 Oracle/Sun 官方 Javadocs 时,他们根本没有提到重写这些方法。这些说明是否隐藏在文档的其他地方?如果是这样,我在哪里可以找到它们?
你不需要重写equals
and hashCode
,但你需要有一致 equals
的andhashCode
方法。
也就是说,如果obj.equals(obj2)
,那么它一定是obj.hashCode() == obj2.hashCode()
。相反(equals()
具有不相等值的非对象hashCode()
)应该尽可能频繁地为真以获得良好的性能,但这不是要求,如果您的对象具有超过 2^32 个状态,则不能总是满足)。
默认值equals()
和hashCode()
方法遵循这一点并具有标识语义 - 对象只有在它们实际上是相同的对象(obj == obj2)时才相等。
如果您想要值语义 - 例如,具有相同状态的两个对象相等,您应该覆盖这些方法。
Collections API 用 equals() 和 hashCode() 来描述合约。如果您希望一个键的多个实例彼此相等,那么您需要按照 Object 类指定的协定重写 equals() 和 hashCode()。
Set 接口描述了它的合约:
更正式地说,集合不包含一对元素 e1 和 e2 使得 e1.equals(e2),并且最多包含一个空元素。正如它的名字所暗示的,这个接口模拟了数学集合抽象。
equals() 和 hashCode() 的合约由 Object 类指定。
在“Effective Java”中,Joshua Bloch 建议您在覆盖hashCode
时始终覆盖equals
,以避免违反这些约定。
在java.lang.Object的合同中对其进行了详细讨论。
在 和 的文档中Set
,Map
它们是它们实现的接口。
该要求不是任意的,它是保证接口的方法按预期工作的唯一方法 - 通过能够判断何时可能是不同的 Java 对象的键应该真正被视为相同的键 - 例如,"abc"
和"ab" + "c"
是不同的对象,但 的实现equals
确保它们被认为是相同的键。至于hashCode
,需要在作为这些接口基础的数据结构中找到有意义的位置。
据我所知,密钥必须是不可变对象。
如果它是可变的,它的哈希码在添加到映射后可以改变。然后地图可能无法找到它
这是一个说明这一点的例子:
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
*/