哪些因素决定新元素是否通过HashSet中的添加来实现?

时间:2013-08-30 20:09:23

标签: java data-structures hashset

我想知道在向HashSet添加新元素(对象)之前检查了哪些因素(1,2或3?)?

如果HashSet中预先存在唯一元素(对象),并且我们尝试添加新对象,那么集合是否只使用equals()或两者来比较哈希码或引用?

  1. HashCode()
  2. equals()
  3. 1和2
  4. 换句话说,

    如果hashTable.add(obj1) => returns true, 和 hashTable.add(obj2) => returns false

    考虑了哪些因素会导致obj2HashSet的存储空间中将其拒绝。

    我试图通过覆盖函数调用来打印日志,但是在添加元素时没有调用equals()。

      public class HashTest {
         int a,b;
         public HashTest(int a, int b){
         this.a=a;
         this.b=b;
       }
    public static void main(String[]args){
        HashSet<HashTest> hashTable=new HashSet<HashTest>();
        HashTest obj1=new HashTest(1, 2);
        HashTest obj2=new HashTest(1, 2);
        System.out.println("1. obj1 hash code:"+obj1.hashCode());
        System.out.println("2. obj2 hash code:"+obj2.hashCode());
        System.out.println("inserting obj1 to the Hash Table:"+hashTable.add(obj1));
        System.out.println("inserting obj2 to the Hash Table:"+hashTable.add(obj2));
    }
    public boolean equals(Object obj){
        System.out.println("***equals called");
        return super.equals(obj);
    }
    
    public int hashCode(){
        System.out.println("***hashCode called");
        return super.hashCode();
    }
      }
    

    结果:

    *** hashCode调用

    1. obj1哈希码:4072869
    2. *** hashCode调用

      1. obj2哈希码:1671711
      2. *** hashCode调用

        将obj1插入哈希表:true

        *** hashCode调用

        将obj2插入哈希表:true

3 个答案:

答案 0 :(得分:1)

必须考虑两者。

考虑以下示例,

  

如果我们有HashSet<String>

     

我们添加 Amy和May 都是字符串对象,相同的HashCode ,但是   他们不相等

  1. hashCode将确定要放入的对象的存储桶。
  2. equals将确定它们是否是同一个对象。

    希望有所帮助。

答案 1 :(得分:1)

两者都使用 1 。这就是Hash-Set (see Hash table)的工作原理 2

hashCode 首先确定使用的存储区,然后equals 始终使用进行最终的相等性测试。 hashCode和equals之间的规则解释了Object契约文档。

因此,如果 hashCode失败(即找到空桶),稍后,equals将失败(即没有等效项目)在桶中),然后该项目“不存在”并且可以添加。这也意味着hashCode测试可以“快速失败”,但不能“快速成功”。


1 可以在等价(==)之前应用身份相等(equals),因为它不会改变契约语义。但是,equals在所有集合类型中使用(除IdentityHashMap之类的罕见例外)作为“终极”测试。

2 有不同种类的哈希表;以上假设是链接,但类似的推理适用于所有哈希策略。

答案 2 :(得分:1)

HashSet使用HashMap,如实施中所示:

public boolean add(E e) {
    return map.put(e, PRESENT)==null;
}

其中mapHashMap的实例。以下是HashMap#put(K, V)的实现:

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);
    @SuppressWarnings("unchecked")
    Entry<K,V> e = (Entry<K,V>)table[i];
    for(; 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;
}

我认为你现在应该能够回答你自己的问题了。