此问题在此处已有答案:
Java HashSet contains duplicates if contained element is modified(7个答案)
6天前关闭
我正在学习java,遇到了一个非常奇怪的问题,我想用我的代码来解释这个沿着会更容易一些
这是我的班级:
class Node
{
private int val;
public Node(int val)
{
this.val = val;
}
public int getVal()
{
return this.val;
}
public void setVal(int newVal)
{
this.val = newVal;
}
@Override
public int hashCode() {
return this.val;
}
@Override
public boolean equals(Object obj) {
System.out.println("Inside equal of " + this.val);
//i expect it will print out when i use set.contains()
if(this.hashCode() == ((Node)obj).hashCode())
{
return true;
}
return false;
}
}
字符串
这是我使用HashSet的主要块,它与Node类一起工作
public class Main
{
public static void main(String[] args)
{
Set<Node> s = new HashSet<>();
Node n1 = new Node(1);
s.add(n1);
/*as i know, when we add a object to the set, we actually add a refference to the origin memory area (the one that n1 points to) to the set*/
if(s.contains(n1))
{
System.out.println("YES");
}
for(Node i : s)
{
i.setVal(5); //i expect n1 to change too and it does
}
for(Node i : s)
{
System.out.println(i.getVal());
}
System.out.println(n1.getVal()); //n1 changes
if(s.contains(n1))
{
System.out.println("Still here");
//This is where i don't understand why this does not print ?
}
System.out.println();
}
}
型
这是我的命令
D:\Desktop\draft\JavaDraft>java Main
YES
5
5
型
我不明白为什么set没有意识到n1仍然在其中,为什么Node类的函数“equals”中的代码没有被触发,因为据我所知,HashSet使用“equals”来获得所有元素的唯一性,对吗?提前谢谢你。
3条答案
按热度按时间dsekswqp1#
HashSet使用“equals”来获得所有元素的唯一性,对吗?
不是
HashSet是HashMap的一个facade,其中的项存储在键集中。HashMap创建并比较来自其内部哈希节点的键hashCode。
一旦项目存储在其hashCode数组元素下,它就在那里。更改hashCode不会替换它。你写的是一个不好的例子如何在HashMap中使用hashCode。
contains
方法将检查底层hashmap键集的键(哈希数组),而不是调用所有存储对象的equals方法。bfhwhh0e2#
这是因为通过修改Node的值,你也改变了hashcode(由于你的hashcode覆盖)。这通常不是这种情况,也不应该是这种情况,因为你不希望hashcode是可变的。它应该是常量和不变的。
HashSet的底层代码使用HashMap,
contains()
使用的内部方法将使用对象的hashcode来确定存储节点的bucket。因此,当您的hashcode设置为值1时,您调用add()
,节点n1存储在bucket 1中。当您将值更改为5时,hashcode现在是5,调用s.contains(n1)
将尝试检查bucket 5中的节点是否为空(null)。正确的方法是删除你实现的hashcode覆盖,让默认实现完成它的工作。另请参阅:
字符串
输出量:
没有哈希码覆盖
型
使用Hashcode override
型
fxnxkyjh3#
你需要理解按引用传递和按值传递的区别。你对hashcode的重写实际上是有效的。但是,你没有创建一个新对象,n1和s中的对象实际上是同一个对象。