hashset 学习心得

package equals.tran;

import java.util.HashSet;
import java.util.Set;

public class Example {

public static void main(String[] args) {
Point p
= new Point(1, 2);
Set
<Point> set = new HashSet<Point>();
set.add(p);
System.out.println(set.contains(
new Point(1, 2)));

p.setX(
2);

System.out.println(set.contains(
new Point(1, 2)));
System.out.println(set.contains(
new Point(2, 2)));

for (Point temp : set) {
if (temp.equals(p)) {
System.out.println(
"OK, temp.equals(p)");
System.out.println(
"temp.x = " + temp.getX() +", temp.y = " + temp.getY());
}
}
}

}

class Point {
private int x;
private int y;

public Point(int x, int y) {
this.x = x;
this.y = y;
}

public int getX() {
return x;
}

public void setX(int x) {
this.x = x;
}

public int getY() {
return y;
}

public void setY(int y) {
this.y = y;
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result
= prime * result + x;
result
= prime * result + y;
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Point other
= (Point) obj;
if (x != other.x)
return false;
if (y != other.y)
return false;
return true;
}

}

答案是

true
false
false
OK, temp.equals(p)
temp.x = 2, temp.y = 2

为什么第2个和第3个事false呢

因为hashset其实底层是HashMap实现的

private transient HashMap<E,Object> map;

hashset的contains方法其实调用了hashMap的containsKey方法,containsKey方法通过getEntry方法查找对象

final Entry<K,V> getEntry(Object key) {
int hash = (key == null) ? 0 : hash(key.hashCode());
for (Entry<K,V> e = table[indexFor(hash, table.length)];
e
!= null;
e
= e.next) {
Object k;
if (e.hash == hash &&
((k
= e.key) == key || (key != null && key.equals(k))))
return e;
}
return null;
}

我们可以看到,首先会根据key对象的hashcode方法生成hash值,再通过hash方法生成一个hash值(h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);这不是很理解),因为我们知道hashMap是通过数组加链表实现的,所以首先通过生成的hash值为索引在数组里面查找位置,在用equals方法判断是否相当,如果不相等,则next继续,找到以后先判断两个对象的hash值是否相等,再判断两个对象是否=或者equals,两个条件是与关系,。

我们再来看例子,首先存进去一个Point(1,2)对象,它的hash值为994,根据hash函数确定在数组的位置(hash函数一般为余上数组的长度),执行

set.contains(new Point(1, 2))

通过1,2算出hash值还是994,找到数组的位子,然后比较,当然是相等的,返回true

然后更改p的y值

p.setX(2);

注意,这里虽然更改了p的y值,但他再hashset里的位子还是没有变化

然后执行

set.contains(new Point(1, 2))

通过1,2算出hash值994,查找到数组的位子,这里是找到了对象的,然后判断hash值是否相等,这里找到的对象的hash值是994,994==994,

但是两个对象既不==也不equals,所以返回false

set.contains(new Point(2, 2))

通过x=2,y=2算出hash值1025,然后查找数组位子上,但这里是找不到对象的,所以返回false

我也纠结了很久,看了源代码,这就是我的理解,有错的地方欢迎指正!

posted @ 2011-05-04 17:45  Evanlee  阅读(574)  评论(1编辑  收藏  举报