Hashset的Hashcode和Equals

时间:2011-03-22 19:48:13

标签: java equals hashcode hashset

请澄清我对Hashset的疑问。请考虑以下代码,

class Person
{
    String name;

    Person(String n)
    {
        name=n; 
    }
    public String getName()
    {
        return name;   
    }

    @Override
    public boolean equals(Object arg0) {

        System.out.println("in equals");

        Person obj=(Person)arg0;

        System.out.println("1st "+getName());
        System.out.println("2nd "+obj.getName());

        if(this.getName().equals(obj.getName()))
        {
                return true;
        }
        return false;
    }


    @Override
    public int hashCode() {

        System.out.println("in hash code");
        System.out.println(" value is "+Integer.valueOf(name.charAt(0)));
        return Integer.valueOf(name.charAt(0));
    }
}

在main中我有以下代码

Person obj1=new Person("bcd");

Person obj2=new Person("cde");

Person obj3=new Person("abc");

Person obj4=new Person("abc");

现在,如果我将这些对象添加到hashset

Set<Person> sset=new HashSet<Person>();

sset.add(obj1);
sset.add(obj4);
sset.add(obj2);
sset.add(obj3);

我收到了这个输出

in hash code                                                                      
value is 98    
in hash code   
value is 97    
in hash code    
value is 99    
in hash code    
value is 97  
in equals  
1st abc     
2nd abc

问题1 :为什么equals()函数只调用一次来检查obj3和obj4?为什么没有检查其余的物体?

问题2 :如果答案是因为它们都有相同的哈希码,那么只会调用equals,那么为什么不调用下面的代码

sset.add(obj1);
sset.add(obj4);
sset.add(obj2);
sset.add(obj4);

输出是:

in hash code  
value is 98  
in hash code   
value is 97   
in hash code   
value is 99   
in hash code  
value is 97 

即使将两个相同的对象添加到具有相同哈希码的哈希集中,它也不会进入equals()方法。

问题3 :我迭代了上面的值并打印了内容,但是没有调用hashcode或equals。当它真的有用来覆盖hashcode和equals方法吗?

问题4 :何时会调用hashCode()equals()

6 个答案:

答案 0 :(得分:53)

  1. 如果equals不同,则无需致电hashCode
  2. 如果hashCode,则无需致电(obj1 == obj2)
  3. hashCode和/或equals只需迭代 - 您不需要比较对象
  4. 需要时区分对象。

答案 1 :(得分:19)

如果您了解集合,特别是HashSets的工作方式,我认为您的问题都将得到解答。集合是唯一对象的集合,Java定义唯一性,因为它不等于任何其他对象(等于返回false)。

HashSet利用哈希码来加快速度。它假设两个相等的对象将具有相同的哈希码。但是,它并不假设具有相同哈希码的两个对象意味着它们是相等的。这就是为什么当它检测到冲突的哈希码时,它只会与具有相同哈希码的集合中的其他对象(在您的情况下为一个)进行比较。

答案 2 :(得分:11)

根据javasourcecode.org的jdk源代码,HashSet使用HashMap作为其内部实现,关于HashSet的put方法的代码如下:

public V put(K key, V value) {
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key.hashCode());
        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;
    }

规则首先检查哈希值,然后检查引用,然后调用equals方法对象将被推入。

答案 3 :(得分:2)

因为在第二种情况下,您添加了两次相同的引用而且HashSet已在HashMap.put()所基于的HashSet中对此进行了检查:

        if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
            V oldValue = e.value;
            e.value = value;
            e.recordAccess(this);
            return oldValue;
        }

正如您所看到的,equals只有在添加的密钥哈希值等于中已存在的密钥时才会被调用,这两个密钥的引用不同。

答案 4 :(得分:1)

您应该了解如何确保已正确实现equals和hashCode。这是一个很好的起点:What issues should be considered when overriding equals and hashCode in Java?

答案 5 :(得分:-3)

请使用其所有方法调试HashSet,您将看到它是如何工作的