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
我也纠结了很久,看了源代码,这就是我的理解,有错的地方欢迎指正!