请教hashcode相关问题

代码如下:
import java.util.*;
public class Hacode {

public static void main(String[] args) {
HashSet hs=new HashSet();
Cat a1=new Cat("aaa",1);
Cat a2=new Cat("aaa",1);
Cat a3=new Cat("bbb",2);
Cat a4=new Cat("bbb",2);
hs.add(a1);
hs.add(a2);
hs.add(a3);
hs.add(a4);
hs.add(a1);

System.out.println(hs.size());
a1.age=22;
hs.remove(a2);
System.out.println(hs.size());

}
}
class Cat {

String name;
int age;
public Cat(String n,int a){
name=n;
age=a;
}

public int hashCode() {
final int PRIME = 31;
int result = 1;
result = PRIME * result + age;
result = PRIME * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final Cat other = (Cat) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}

}

为什么明明已经把a1给remove了还是输出hs的size是2呢?我只知道这与hashcode有关系,但是真的没彻底搞明白。请哪位热心高人给予详细解答呢?谢谢啊

不知道你有没有看过里面的源码,额。。。

这样说吧。

HashSet的add内部使用的是HashMap。
Hashmap内部使用的存放数据其实是个数组。
table[].

刚开始put
c1=Cat("cat",1)
hashCode假设为1.
那么通过一定的对这个hashCode算法算出来的hash值假设为11.

也就是table[11]=c1.

现在你把c1的改成Cat("cat",20)
假设这个时候hashCode变成20.

那么当你用现在这个去remove的时候,通过对这个hashCode的算法算出来的hash值
就不是11了,假设为20。

那这个时候remove就会去找
table[20],把这个东西给remove掉。可以table[20]这个时候并没有放东西。
所以remove不掉任何东西,就false了。

要不你看下源码么,应该就会明白了,关注下hashMap在put的时候hash函数。

这个跟hashSet的实现有关系。

如果你用hashMap的思维去思考就会陷入误区。

我先给你简单说个例子。

HashMap m=new HashMap();

Cat cat1=new Cat("aaa",1);
Cat cat2=new Cat("aaa",1);

m.put(cat1,"cat1");//1
m.put(cat2,"cat2");//2

因为你这里进行了重载,所以cat1和cat2的hashCode是一样的,并且equals,也就是说第一步执行后,第二步再执行的时候,发现这个key已经有了,就不管了。
去改这个key对应的value。

所以这里的key实际存放的还是cat1.

你接下来的代码
a1.age=22;//1
hs.remove(a2);//2

注意看第一步,因为现在的key实际存放的就是a1,
所以这里更改了之后,现在的key的age就是22了。

第二步,remove a2的代码。注意这个时候拿a2去跟a1比,已经不相等了,而且hashcode也不等了,所以这个remove是false的,不信你打印看看。

我前面提到hashMap就是因为hashSet内部是用它实现的。

另外我再建议里,在执行:
a1.age=22;//1
之后,打印下现在set里面的key是啥,你就明白了。

Iterator it1 = hs.iterator();
while (it1.hasNext()) {
Cat c = it1.next();
System.out.println(c);
}

求知欲很好哇,大家一起探讨下,不过这里还是不理解吗?

a1.age=22;//1
hs.remove(a1);//2

这样,
我用汉语跟你解释一下。

hashSet放了一个年龄为1的猫。

后来这个猫长到了22岁。

再去那个hashSet去把这个22岁的猫给remove掉,你觉得会成功吗?

Cat("a",1)
是hashSet里面存的。

但是你改成
Cat("a",22)
之后它的hashCode就变了,你根据这个新的hashCode去remove的,必然找不到啊。。。

用Hash之类的东西,remove的东西最好不要变。不然得不到你想要的结果的。