java 如果 hashCode() 未被覆盖,HashSet 允许插入重复项
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11114693/
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
HashSet allows duplicate item insertion if hashCode() is not overridden
提问by Dhwaneet Bhatt
class temp {
int id;
public int getId() {
return id;
}
temp(int id) {
this.id = id;
}
public void setId(int id) {
this.id = id;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
temp other = (temp) obj;
if (id != other.id)
return false;
return true;
}
}
public class testClass {
public static void main(String[] args) {
temp t1 = new temp(1);
temp t2 = new temp(1);
System.out.println(t1.equals(t2));
Set<temp> tempList = new HashSet<temp>(2);
tempList.add(t1);
tempList.add(t2);
System.out.println(tempList);
}
The program adds both the elements to the Set. I was shocked at first because while adding methods to set, equals method is invoked.
该程序将这两个元素都添加到 Set 中。一开始我很震惊,因为在添加方法到 set 时,调用了 equals 方法。
But then I overrode the hashCode method:
但后来我覆盖了 hashCode 方法:
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
return result;
}
And then it did not add. This is surprising as the Javadoc of Set and add() method says that it checks only equals() while adding into the Set.
然后它没有添加。这是令人惊讶的,因为 Set 和 add() 方法的 Javadoc 说它在添加到 Set 时只检查 equals()。
And this is the javadoc for add():
这是 add() 的 javadoc:
/**
* Adds the specified element to this set if it is not already present.
* More formally, adds the specified element <tt>e</tt> to this set if
* this set contains no element <tt>e2</tt> such that
* <tt>(e==null ? e2==null : e.equals(e2))</tt>.
* If this set already contains the element, the call leaves the set
* unchanged and returns <tt>false</tt>.
*
* @param e element to be added to this set
* @return <tt>true</tt> if this set did not already contain the specified
* element
*/
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
Then I realized that the HashSet is implemented as a HashMap and in the map, the hashCode of the object is used as the key. So, it is treating them using different keys if you dont override hashCode.
然后我意识到 HashSet 是作为 HashMap 实现的,并且在映射中,对象的 hashCode 用作键。因此,如果您不覆盖 hashCode,它将使用不同的键来处理它们。
Shouldn't this be in the documentation of the add() method or that of HashSet?
这不应该在 add() 方法或 HashSet 的文档中吗?
采纳答案by Kallja
It kind of is documented. See the documentation for java.lang.Object, where it says on hashCode()
:
它有点被记录在案。请参阅java.lang.Object的文档,其中说hashCode()
:
If two objects are equal according to the equals(Object)method, then calling the hashCode method on each of the two objects must produce the same integerresult.
如果根据 equals(Object)方法两个对象相等,则对两个对象中的每一个调用hashCode 方法必须产生相同的整数结果。
Additionally the following is found in the documentation for the Object.equals(Object)
method:
此外,在该Object.equals(Object)
方法的文档中还可以找到以下内容:
Note that it is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes.
请注意,每当重写此方法时,通常都需要重写 hashCode 方法,以维护 hashCode 方法的一般约定,即相等的对象必须具有相等的哈希码。
In other words, if with your class when instanceA.equals(instanceB) == true
and instanceA.hashCode() != istanceB.hashCode()
you are in fact violating the contract of the Object class.
换句话说,如果你上课的时候instanceA.equals(instanceB) == true
和instanceA.hashCode() != istanceB.hashCode()
你其实违反了Object类的合同。
回答by Hyman
Just take a look also at equals()
documentation:
只需看看equals()
文档:
Note that it is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes.
请注意,每当重写此方法时,通常都需要重写 hashCode 方法,以维护 hashCode 方法的一般约定,即相等的对象必须具有相等的哈希码。
The fact is that equals()
and hashCode()
are strongly linked. Both should always be considered when working with one of them to avoid these consistency issues.
事实是,equals()
和hashCode()
是密切相关的。在使用其中之一时应始终考虑两者以避免这些一致性问题。
回答by n0rm1e
If you override equals() you mustoverride hashCode() as well.
如果您覆盖 equals(),您也必须覆盖 hashCode()。
There are some restrictions placed on the behavior of equals() and hashCode(), which are enumerated in the documentation for Object. In particular, the equals() method must exhibit the following properties:
对 equals() 和 hashCode() 的行为有一些限制,它们在 Object 的文档中列举。特别是,equals() 方法必须具有以下属性:
- Symmetry: For two references, a and b, a.equals(b) if and only if b.equals(a)
- Reflexivity: For all non-null references, a.equals(a)
- Transitivity: If a.equals(b) and b.equals(c), then a.equals(c)
- Consistency with hashCode(): Two equal objects must have the same hashCode() value
- 对称性:对于两个引用,a 和 b,a.equals(b) 当且仅当 b.equals(a)
- 自反性:对于所有非空引用,a.equals(a)
- 传递性:如果 a.equals(b) 和 b.equals(c),则 a.equals(c)
- 与 hashCode() 的一致性:两个相等的对象必须具有相同的 hashCode() 值
See thisfor more details.
有关更多详细信息,请参阅此内容。
回答by Priyank Doshi
They (the javadoc guys) might have pre-assumed that when they say (at the documentation of add()
method in HashSet
)
他们(javadoc 人员)可能已经预先假设了当他们说(在add()
方法的文档中HashSet
)
(e==null ? e2==null : e.equals(e2))
the hashCode()
is inherently equal for both of them.
这hashCode()
两者本质上是平等的。