首页 新闻 会员 周边 捐助

hashset添加不重复元素

0
[待解决问题]
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插入

 

 

codeZhu的主页 codeZhu | 菜鸟二级 | 园豆:202
提问于:2015-05-07 20:30
< >
分享
所有回答(3)
0

你那equals方法有问题啊 name.equals(p.getName()) 相等还返回false?

单恋 | 园豆:678 (小虾三级) | 2015-05-07 21:06

我是故意这么写的啊,目的就是让哈希值相同的时候再进行equals判断时误认为两个相等的对象不等,然后插入到set中,可是上面的没有插入set中,我想知道这是为什么

支持(0) 反对(0) codeZhu | 园豆:202 (菜鸟二级) | 2015-05-07 21:44

@codeZhu: http://blog.csdn.net/ning109314/article/details/17354839 你看看这个

支持(0) 反对(0) 单恋 | 园豆:678 (小虾三级) | 2015-05-07 21:52

@单恋: 写之前看过这篇文章,里面说的和我上面说的一样,首先判断hash值,不等就插入,相等就再判断equals,equals相等就不插入,不等就再插入。上面我写的就是为了验证这句话,可是我人为让equals不等,为什么不能插入?

支持(0) 反对(0) codeZhu | 园豆:202 (菜鸟二级) | 2015-05-07 21:58

@codeZhu: 都说了 先判断hash值啊 两个hash值相同了 都不会判断后面的equals了

支持(0) 反对(0) 单恋 | 园豆:678 (小虾三级) | 2015-05-07 22:00

@单恋: 额,你确定是这样的,hash值相同了就不判断了吗?

支持(0) 反对(0) codeZhu | 园豆:202 (菜鸟二级) | 2015-05-07 22:04

@codeZhu: 你试试啊 你在hashcode方法里面输出一句话啊 还有equals里面  你看看它执不执行

支持(0) 反对(1) 单恋 | 园豆:678 (小虾三级) | 2015-05-07 22:06

@单恋: hash相同是执行equals的。

支持(0) 反对(0) codeZhu | 园豆:202 (菜鸟二级) | 2015-05-07 22:09

@单恋: 你看看这篇文章http://www.cnblogs.com/Jc-zhu/p/4487988.html

支持(0) 反对(0) codeZhu | 园豆:202 (菜鸟二级) | 2015-05-08 16:12
0

其实你如果跟踪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运算了

老刘2018 | 园豆:202 (菜鸟二级) | 2015-06-02 16:39
0

你这个程序与你怎么重写 equals一点关系都没有,因为p1与p2就是同一个对象。两次添加的是同一个对象,肯定不会成功了。

乐享程序员 | 园豆:930 (小虾三级) | 2015-06-29 13:49
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册