我对一个概念感到困惑。有人可以请点亮它。
问题:如果Hashmap
的密钥是不可变对象(由开发人员创建),那么我们是否需要覆盖hashcode()
和equals()
?或者将不可变字段作为键来解决覆盖hashcode()
和equals()
的问题?
感谢。
答案 0 :(得分:4)
是。我在这里引用java.lang.Integer
的例子。如果我们希望将整数(稀疏)映射到对象,我们会使用HashMap<Integer, Object>
行的内容。如果我们添加条目Integer.valueOf(2)=>"foo"
,并尝试使用new Integer(2)
检索它,则需要重写的哈希码和等号。
答案 1 :(得分:1)
这些问题略有不同。
与hexafraction's answer一样,如果两个不同的实例可以被认为是相同的,那么使用不可变实例不足以让您跳过编写equals
和hashCode
的步骤。 new Integer(2)
应始终等于其他new Integer(2)
,即使对象是不可变的且实例不同。
也就是说,有一些&#34;实例控制的类&#34;其中实例标识的默认行为就足够了:
在编译时创建枚举实例,每个值一个。 (理论上)没有办法产生任何其他实例。如果没有两个实例相等,则equals
和hashCode
的默认实现就足够了。 Enum instances aren't compiler-guaranteed to be immutable, but you should treat them as such.
如果您的班级实例保证彼此不同,无论他们是否不可变,您都可以跳过equals
和hashCode
。可以想象一个Car对象,其中CarFactory生成的每辆Car都不同。
作为上述内容的一种变体,如果你足够紧密地控制对象实例化,相同的表示总是给出完全相同的实例,那么这可以被认为是足够的:
public class MyClass {
private MyClass(int foo) { /* ... */ }
private static final Map<Integer, MyClass> instanceCache = new HashMap<>();
/** Returns an existing MyClass(foo) if present; otherwise, creates one. */
public synchronized static MyClass create(int foo) {
// Neither leak-proof or thread-safe. Just demonstrating a concept.
if (instanceCache.contains(foo)) {
return instanceCache.get(foo);
}
MyClass newMyClass = new MyClass(foo);
instanceCache.put(foo, newMyClass);
return newMyClass;
}
}
答案 2 :(得分:0)
试一试,看看:
public class OverrideIt
{
static class MyKey
{
public final int i; // immutable
public MyKey(int i)
{
this.i = i;
}
}
public static void main(String[] args)
{
Map<MyKey, String> map = new HashMap<MyKey, String>();
map.put(new MyKey(1), "Value");
String result = map.get(new MyKey(1));
System.out.println(result); // null
}
}
打印出null
,表明我们无法查找我们的值。这是因为MyKey
的两个副本不相等且没有相同的哈希码,因为我们没有覆盖.equals()
和hashcode()
。
答案 3 :(得分:0)
事实
Entry[]
(条目是LinkedList的种类)。你在评论部分同意
"Is it possible that you'll store an object using one key,
and then try to retrieve it using a key which is an identical object,
but not the same object"
即使两个键具有相同的值,实例也是不同的。那么你可能根据合同对两个密钥都有不同的哈希码(事实4)。因此,您将在数组中具有不同的位置(规则2)
map.put(new key(1),"first element");
此处,键对象不会覆盖,因此它将返回每个实例的哈希码unquie。 (为了避免过于复杂化,假设哈希码返回为000025.所以Entry [25]是&#34; First Element&#34;)
map.get(new key(1))
现在这个新密钥可能会将哈希码值返回为000017
,所以它会尝试从Entry [17]获取值并返回null(不例外)。
注意为了简单起见,我只是将示例作为000025和000017,实际上hashmap会重新访问哈希码并根据数组大小进行更改
到目前为止,我们还没有讨论过Key是可变的还是不可变的。无论密钥是可变的还是不可变的
If you store an object using one key,and then try to retrieve it using a key
which is an identical object,but not the same object
您需要覆盖哈希码并确保它返回相同的整数,以便它可以找到相同的桶(在Array中的位置)并获取该元素。同样适用于从条目中获取正确元素的等于