问题 2 的答案很简单——是的,您可以使用任何您喜欢的对象。具有字符串类型键的映射被广泛使用,因为它们是命名服务的典型数据结构。但一般来说,您可以映射任何两种类型,例如Map<Car,Vendor>
or Map<Student,Course>
。
对于 hashcode() 方法,就像之前回答的那样 - 每当您覆盖 equals() 时,您都必须覆盖 hashcode() 以遵守合同。另一方面,如果您对 equals() 的标准实现感到满意,那么您不应该触摸 hashcode()(因为这可能会破坏合同并导致不相等对象的哈希码相同)。
实用的旁注:eclipse(可能还有其他 IDE)可以根据类成员为您的类自动生成一对 equals() 和 hashcode() 实现。
编辑
对于您的附加问题:是的,完全正确。查看 HashMap.get(Object key); 的源代码 它调用 key.hashcode 来计算内部哈希表中的位置(bin)并返回该位置的值(如果有的话)。
但是要小心“手工制作”的 hashcode/equals 方法 - 如果您使用对象作为键,请确保 hashcode 之后不会更改,否则您将无法再找到映射的值。换句话说,用于计算等号和哈希码的字段应该是最终的(或在创建对象后“不可更改”)。
String name
假设我们与and有联系,String phonenumber
我们使用这两个字段来计算 equals() 和 hashcode()。现在我们用他的手机号码创建“John Doe”并将他映射到他最喜欢的甜甜圈店。hashcode() 用于计算哈希表中的索引(bin),这就是甜甜圈店的存储位置。
现在我们知道他有一个新的电话号码,我们更改了 John Doe 对象的电话号码字段。这会产生一个新的哈希码。这个哈希码解析为一个新的哈希表索引——这通常不是存储 John Does 最喜欢的甜甜圈店的位置。
问题很明显:在这种情况下,我们希望将“John Doe”映射到 Donut 店,而不是“具有特定电话号码的 John Doe”。因此,我们必须小心自动生成的等值/哈希码,以确保它们是我们真正想要的,因为它们可能会使用不需要的字段,从而给 HashMaps 和 HashSets 带来麻烦。
编辑 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;
}