返回信息流import java.util.HashSet;
public class MyClass
{
public String s;
public MyClass(String s)
{
this.s = s;
}
public int hashCode()
{
return s.hashCode();
}
public boolean equals(Object obj)
{
if(obj == null)
return false;
if(!(obj instanceof MyClass))
return false;
MyClass other = (MyClass)obj;
if(s == null)
{
return false;
}
return(s.equals(other.s));
}
public static void main(String[] args)
{
HashSet<MyClass> set = new HashSet<MyClass>();
MyClass mc1 = new MyClass("a");
set.add(mc1);
mc1.s = "b";
MyClass mc2 = new MyClass("b");
if(set.contains(mc2))
{
System.out.println("True");
}
else
{
System.out.println("False");
}
}
}
这是一条镜像帖。来源:北邮人论坛 / java / #29514同步于 2014/4/23
该镜像源已超过 30 天没有更新,可能在源站已被删除。
Java机器人发帖
True or False? and WHY???
dUKE
2014/4/23镜像同步4 回复
订阅后,新回复会通过你的通知中心匿名送达。
4 条回复
答案是false,当MyClass mc1 = new MyClass("a")时,执行顺序为 先执行构造函数方法,再执行hashCode()方法 。此时由于你重写了hashCode()方法,使得该对象的hashCode值为String s的哈希值。因此set.add(mc1)时,mc1放置到了以“a”的哈希值计算的位置。
即使你之后你改变了mc1.s="b",并没有让mc1的哈希值改变。因此你MyClass mc2 = new MyClass("b")时,并没有覆盖掉mc1,同时mc2没有add到set,所以执行else中的语句。
你可以通过在构造方法,hashCode添加打印语句来验证。
thx a lot!!!
您的回复给我启发很大。但是似乎有个小问题~
即使你之后你改变了mc1.s="b",并没有让mc1的哈希值改变。
应该是mc1的哈希值已经变了吧?(所谓mc1的哈希值不就是调用hashCode()的返回值么?)
但是结果确实是False
我猜原因和您说的很接近:
在向set存储时,位置是使用之前的哈希值得到的。
之后改变了mc1.s使得其哈希值发生了变化。
调用contains方法时,找的是之后哈希值指向的位置,这是虽然mc1和mc2有相同的哈希值、且true == mc1.equeals(mc2),但在该位置上根本没有存储东西,所以返回false
另外刚才找到Set的API文档里有这么一段话
Note: Great care must be exercised if mutable objects are used as set elements. The behavior of a set is not specified if the value of an object is changed in a manner that affects equals comparisons while the object is an element in the set.
这样结果是False也许就是因为HashSet的实现方法(用了哈希散列存储)~~
【 在 MrLee 的大作中提到: 】
: 答案是false,当MyClass mc1 = new MyClass("a")时,执行顺序为 先执行构造函数方法,再执行hashCode()方法 。此时由于你重写了hashCode()方法,使得该对象的hashCode值为String s的哈希值。因此set.add(mc1)时,mc1放置到了以“a”的哈希值计算的位置。
: 即使你之后你改变了mc1.s="b",并没有让mc1的哈希值改变。因此你MyClass mc2 = new MyClass("b")时,并没有覆盖掉mc1,同时mc2没有add到set,所以执行else中的语句。
: 你可以通过在构造方法,hashCode添加打印语句来验证。
进来学习
我们知道:
当一个对象(A)加进HashSet(HS)的时候,会按照当前的hashcode(111)分配内存空间(0X00FF)来存储,
那就是说,得出False结论的原因是基于:
如果加进来的对象(A)后来因为改变内容而使得它的hashcode改变(- >222)的话,并不会相应的改变它在HS的存储位置(0X00FF),
在这种情况下,即使在cantains方法使用该对象的当前引用作为参数去HashSet集合中检索对象,也将返回找不到对象的结果,222 != 111,
再者,这也会导致从HS集合中单独删除当前对象,但是HS给原来对象分配的内存却没有被释放掉,从而会造成内存泄露。