问题2的答案很简单 - 是的,您可以使用您喜欢的任何对象。具有 String 类型键的映射被广泛使用,因为它们是命名服务的典型数据结构。但通常,您可以映射任意两种类型,如 或 。Map<Car,Vendor>
Map<Student,Course>
对于hashcode()方法,它就像之前回答的那样 - 每当你覆盖equals()时,你必须覆盖hashcode()来遵守契约。另一方面,如果你对 equals() 的标准实现感到满意,那么你不应该接触 hashcode() (因为这可能会破坏契约并导致不平等对象的哈希码相同)。
实用的旁注:eclipse(可能还有其他IDE)可以为您的类自动生成一对equals()和hashcode()实现,只需基于类成员。
编辑
对于您的其他问题:是的,没错。查看HashMap.get(Object key)的源代码;它调用key.hashcode来计算内部哈希表中的位置(bin),并返回该位置的值(如果有的话)。
但是要小心“手工制作”的哈希码/等于方法 - 如果您使用对象作为键,请确保哈希码之后不会更改,否则您将找不到映射的值。换句话说,用于计算等于和哈希码的字段应该是最终的(或在创建对象后“不可更改”)。
假设,我们与 和 有联系,并且我们使用这两个字段来计算 equals() 和 hashcode()。现在,我们用他的手机号码创建“John Doe”,并将他映射到他最喜欢的甜甜圈店。hashcode()用于计算哈希表中的索引(bin),这就是甜甜圈店的存储位置。String name
String phonenumber
现在我们知道他有一个新的电话号码,我们更改了 John Doe 对象的电话号码字段。这会产生一个新的哈希码。这个哈希代码解析为一个新的哈希表索引 - 这通常不是John Do最喜欢的甜甜圈店存储的位置。
问题很明显:在这种情况下,我们希望将“John Doe”映射到甜甜圈商店,而不是“具有特定电话号码的John Doe”。因此,我们必须小心自动生成的等于/哈希码,以确保它们是我们真正想要的,因为它们可能会使用不需要的字段,从而给HashMaps和HashSet带来麻烦。
编辑 2
如果将对象添加到 HashSet,则 Object 是内部哈希表的键,该值已设置但未使用(只是 Object 的静态实例)。以下是 openjdk 6 (b17) 中的实现:
// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();
private transient HashMap<E,Object> map;
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}