public class HashcodeTest { public static void main(String[] args) { HashSet<Person> set1 = new HashSet<Person>(); Person p1 = new Person(); Person p2 = p1; p1.setName("mike"); if(set1.add(p1)){ System.out.println("p1"); } if(set1.add(p2)){ System.out.println("p2"); } System.out.println(p1.equals(p2)); Iterator<Person> i = (Iterator<Person>) set1.iterator(); while(i.hasNext()){ System.out.println(i.next()); } } } class Person{ String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public boolean equals(Object obj) { // TODO Auto-generated method stub Person p = (Person)obj; if(name.equals(p.getName())){ return false; }else { return true; } } public String toString() { return name+" "+hashCode(); } }
HashSet不能添加重复的元素,当调用add(Object)方法时候,首先会 调用Object的hashCode方法判hashCode是否已经存在,如不存在则直接插入元素;如果已存在则调用Object对象的equals方法 判断是否返回true,如果为true则说明元素已经存在,如为false则插入元素。
在上面的代码中,p1与p2的hash值一样,人的重写equals()使返回false,为什么hashset不能将p2插入
你那equals方法有问题啊 name.equals(p.getName()) 相等还返回false?
我是故意这么写的啊,目的就是让哈希值相同的时候再进行equals判断时误认为两个相等的对象不等,然后插入到set中,可是上面的没有插入set中,我想知道这是为什么
@codeZhu: http://blog.csdn.net/ning109314/article/details/17354839 你看看这个
@单恋: 写之前看过这篇文章,里面说的和我上面说的一样,首先判断hash值,不等就插入,相等就再判断equals,equals相等就不插入,不等就再插入。上面我写的就是为了验证这句话,可是我人为让equals不等,为什么不能插入?
@codeZhu: 都说了 先判断hash值啊 两个hash值相同了 都不会判断后面的equals了
@单恋: 额,你确定是这样的,hash值相同了就不判断了吗?
@codeZhu: 你试试啊 你在hashcode方法里面输出一句话啊 还有equals里面 你看看它执不执行
@单恋: hash相同是执行equals的。
@单恋: 你看看这篇文章http://www.cnblogs.com/Jc-zhu/p/4487988.html
其实你如果跟踪HashSet的源代码实现就会发现原因
public class HashSet extends AbstractSet implements Set, Cloneable, java.io.Serializable{ static final long serialVersionUID = -5024744406713321676L; private transient HashMap<E,Object> map; // Dummy value to associate with an Object in the backing Map private static final Object PRESENT = new Object(); //此处省略N行代码 public boolean add(E e) { return map.put(e, PRESENT)==null; } //此处省略N行代码 } HashMap源代码中put实现 : public V put(K key, V value) { if (table == EMPTY_TABLE) { inflateTable(threshold); } if (key == null) return putForNullKey(value); int hash = hash(key); int i = indexFor(hash, table.length); for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++; addEntry(hash, key, value, i); return null; }
请注意if判断,里面有个(k = e.key) == key || key.equals(k) ,因为你的代码中p1与p2其实是一个对象,都指向同一个对象,所以(k = e.key) == key是返回true,对于||或运算也就没必要再判断key.equals(k)执行equals运算了
你这个程序与你怎么重写 equals一点关系都没有,因为p1与p2就是同一个对象。两次添加的是同一个对象,肯定不会成功了。