为什么 java 中的默认 hashcode() 不好?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15978026/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why is the default hashcode() in java bad?
提问by HukeLau_DABA
if I remember correctly the default hashCode() implementation in java of an object of type Object() is to return the memory address of the object. When we create our own classes, I read that we want to override hashCode() so that when we insert them into a hash related collection like HashMap() it will work properly. But why is a memory address bad?
如果我没记错的话,Java 中 Object() 类型的对象的默认 hashCode() 实现是返回对象的内存地址。当我们创建自己的类时,我读到我们想要覆盖 hashCode() 以便当我们将它们插入到像 HashMap() 这样的散列相关集合中时,它会正常工作。但是为什么内存地址不好呢?
Sure we will EVENTUALLY run out of memory and you'll have collisions, but the only case where I see this being a problem is where you are dealing with TONS of data and have very little memory, and then it would START to affect performance because hash related collections in java resolve collisions by chaining(a bucket will link to a list of values that resolved to the same hashcode/index).
当然我们最终会耗尽内存并且你会发生冲突,但我认为这是一个问题的唯一情况是你正在处理大量数据并且内存很少,然后它会开始影响性能,因为java中散列相关的集合通过链接来解决冲突(存储桶将链接到解析为相同散列码/索引的值列表)。
回答by John Kugelman
The default implementation works fine if every object is unique. But if you override equals() then you are implicitly saying that objects with different addresses can be equivalent to each other. In that case you have to also override hashCode().
如果每个对象都是唯一的,则默认实现工作正常。但是如果你覆盖了 equals() ,那么你就是在暗示具有不同地址的对象可以彼此等价。在这种情况下,您还必须覆盖 hashCode()。
Think of the String class.
想想 String 类。
String s1 = new String("foo");
String s2 = new String("foo");
These two strings are equal and so their hash codes must be equal. But they are distinct objects with different addresses.
这两个字符串相等,因此它们的哈希码必须相等。但它们是具有不同地址的不同对象。
s1 == s2 // false, different addresses
s1.equals(s2) // true, same contents
Using their addresses as hash codes would be an error. Therefore, String overrides hashCode() to ensure that equal strings have equal hash codes. This helps meet hashCode()'s contract, which is:
使用他们的地址作为哈希码将是一个错误。因此,String 会覆盖 hashCode() 以确保相等的字符串具有相等的哈希码。这有助于满足 hashCode() 的契约,即:
If
a.equals(b)
is true, thena.hashCode() == b.hashCode()
.
如果
a.equals(b)
是真的,那么a.hashCode() == b.hashCode()
。
Bottom line:If you override equals(), also override hashCode().
底线:如果您覆盖equals(),也覆盖hashCode()。
回答by user640554
Exact key objects used while putting objects into hashmap may not be available to access the map later on in your program. So you will end up overriding equals method. When you override equals method you make sure that their hashcodes are also equal, otherwise you cannot retrieve the objects from the hashmap.
将对象放入 hashmap 时使用的确切关键对象可能无法用于稍后在您的程序中访问该映射。所以你最终会覆盖 equals 方法。当您覆盖 equals 方法时,请确保它们的哈希码也相等,否则您无法从哈希图中检索对象。
回答by Liran NESTA
Deciding which hashCode() implementation should be used by the data structure is implicitly a part of the hashmap API.
决定数据结构应该使用哪个 hashCode() 实现隐含地是 hashmap API 的一部分。
Providing certain API with information that isn't strictly handled by you, takes the control out of your hands.
向某些 API 提供并非由您严格处理的信息,会使您无法控制。
Using the default hashCode() implementation couples the keysthat you wish to manage to the memory address, which isn't handled by you , and you don't have any control on.
使用默认的hashCode()实现夫妻的钥匙,你要管理的内存地址,这是不是你处理,你没有任何控制。
Say that one day you will want to use a certain memory optimizer, which moves objects around memory for consistency and better performance. You will not be able to use your data structure anymore, for it holds the original hashed addresses of your keys.
假设有一天你会想要使用某种内存优化器,它会在内存中移动对象以获得一致性和更好的性能。您将无法再使用您的数据结构,因为它保存着您密钥的原始散列地址。
In a more practical point of view,
从更实际的角度来看,
In order to retrieve values from the data structure throughout the program, you will have to keep the references to all of the keys that you have previously inserted (by using another data structure). You will not be able to use keys that are "similar" in terms of object state.
为了在整个程序中从数据结构中检索值,您必须保留对先前插入的所有键的引用(通过使用另一个数据结构)。您将无法使用在对象状态方面“相似”的键。
Person steve1 = new Person("Steve","21","engineer");
Person steve2 = new Person("Steve","21","engineer");
map.put(steve1,"great worker");
map.get(steve2);
// returns null because "steve2" is not considered a key like "steve1"
map.get(steve1);
// returns "great worker"
回答by RiaD
While you don't use equals
method it's OK to not define hashCode
, but after that contract of hashCode
is to give same result for objects, that equals. You can't be sure it will, so you need to rewrite it yourself
虽然您不使用equals
method 也可以不定义hashCode
,但是在该契约之后hashCode
是为对象提供相同的结果,即等于。你不能确定它会,所以你需要自己重写