是否可以在HashSet中输入重复值?

时间:2014-10-05 07:59:12

标签: java set hashcode hashset

我试图通过修改hashCode()和equals()方法()来在HashSet中添加重复值?

我试过下面的代码

public class dupSet {
    static Set set= new HashSet();
    @Override
    public int hashCode() {
        return (int) (100*Math.random());
    }
    @Override
    public boolean equals(Object obj) {
        return false;
    }
    public static void main(String[] args) throws ParseException {
        set.add("a");
        set.add("b");
        set.add("a");
      System.out.println(set);
    }

}

根据我的理解,对于两个重复的" a" HashSet将首先获取hashCode()以获取正确的存储桶,然后检查equals()的值,如果equals返回true,则它将不会添加,但如果它返回false则会添加。 因此,为了向我的Set添加重复值,我重写equals(),它总是返回false,但仍设置不允许重复值?

3 个答案:

答案 0 :(得分:2)

hashCode方法始终返回零。看看Math.random()

的范围

其次,您不会覆盖添加的元素的equalshashCode。您实际上添加了String。要使工作正常,您必须实现一个类并将该类的实例添加到HashSet。实现的类需要覆盖equalshashSet方法,而不是主类。

第三,正如评论中所述,你不应该做你正在做的事情。你真正想要的是ArrayList。通过这种方式实施equalshashCode方法,基本合同就会被打破。

答案 1 :(得分:1)

你希望Set中的对象包含我认为的重复项(如果只是为了好奇心继续阅读,否则只需选择其他集合。this可能有帮助)

让我做一些更正:

public class DupSet<E extends Comparable<E>>{
 private Set<E> mySet = new HashSet<>();

 //Implement add, remove and size
}

public class MyNeverEqualClass implements Comparable<MyNeverEqualClass>{
  private static int stupidHash = 0;
  private int num;

  public MyNeverEqualClass(int num){
   this.num = num;
  }

  @Override
  public int compareTo(MyNeverEqualClass other){
   double rnd = Math.random()*3 + 1
   return (rnd > 1.5)? 1:-1;
  }

  @Override
  public boolean equals(MyNeverEqualClass other){
   return false;
  }

  @Override
  public int hashCode(){
   return stupidHash++;
  }
 }

 public static void main(String[] args){
  MyNeverEqualClass a = new MyNeverEqualClass(1);
  MyNeverEqualClass b = new MyNeverEqualClass(1);
  DupSet<MyNeverEqualClass> set = new DupSet<>();
  set.add(a);
  set.add(b);
 }

答案 2 :(得分:1)

  

我阅读了源代码,从中我能够理解它的工作原理   所以需要一些帮助   

首先

  

Set是定义明确且不同的对象的集合


所以不存在添加重复值的问题。但是如果你有兴趣了解java如何实现/实现这个约束,那么你可以开始挖掘源代码。

HashSet由HashMap支持,这意味着它将其添加,删除等操作委托给HashMap。现在当您调用set.add("a");

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

,然后调用HashMap#put

public V put(K key, V value) {
    return putVal(hash(key), key, value, false, true);
}

put方法首先使用

计算对象的哈希码
static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

一旦计算出hashCode,它就会调用

final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict)

在这个方法里面,它把值放在这个条件

if ((p = tab[i = (n - 1) & hash]) == null)

为true,然后递增modCount(存储HashMap结构修改的次数),检查是否需要resize地图,然后调用afterNodeInsertion并返回null


现在当你调用set.add("b");时,相同的逻辑再次运行,但这次是final V putVal方法中的条件

if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))

保持为真,因此,代码

if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }

检测现有映射,从而返回oldValue。因此阻止添加重复值。