使用指定方法的Java HashSet

时间:2011-01-02 02:38:53

标签: java hash

我有一个基本的类'HistoryItem',如下所示:

public class HistoryItem
  private Date startDate;
  private Date endDate;
  private Info info;
  private String details;

  @Override
  public int hashCode() {
    int hash = (startDate == null ? 0 : startDate.hashCode());
    hash = hash * 31 + (endDate == null ? 0 : endDate.hashCode());
    return hash;
  }
}

我目前正在使用HashSet从startDate&上的ArrayList中删除重复项。 endDate字段,它正常工作。

但是我还需要删除不同字段的重复项(信息和详细信息)。

我的问题是这个 有没有办法指定HashSet将使用的不同方法来代替hashCode()? 像这样:

public int hashCode_2() {
  int hash = (info == null ? 0 : info.hashCode());
  hash = hash * 31 + (details == null ? 0 : details.hashCode());
  return hash;
}

Set<HistoryItem> removeDups = new HashSet<HistoryItem>();
removeDups.setHashMethod(hashCode_2);

或者我还有另一种方法吗?

6 个答案:

答案 0 :(得分:2)

您可以使用不同的HistoryItem实现围绕GetHashCode创建一个包装类,然后围绕原始集合中的每个项目创建一个包装器的HashSet。

答案 1 :(得分:1)

一些事情。首先,如果要覆盖hashCode(),必须覆盖equals()。这个很重要。其次,如果您正在处理不同的字段,那么您应该为每个字段使用不同的HashSet。所以你可以这样迭代地图:

HashSet<String> info;
HashSet<String> details;
for (HistoryItem h:map){
  if(info.contains(h.getInfo()){
    // this is a dup

  }
  if (details.contains(h.getDetails()){
    // this is a dup
  }
  info.add(h.getInfo());
  details.add(h.getDetails());
}

答案 2 :(得分:1)

我最终使用了GNU Trove

需要更改代码。

实施TObjectHashingStrategy的新类(包含HashCodeEquals方法)。

public class HistoryItemDuplicateInfo
implements TObjectHashingStrategy<HistoryItem> {

  @Override
  public int computeHashCode(HistoryItem obj) {
     ...
  }

  @Override
  public boolean equals(HistoryItem arg0, HistoryItem arg1) {
    ...
  }
}

然后使用具有指定策略的THashSet对象删除重复项。

THashSet<HistoryItem> hs = new THashSet<HistoryItem>(new HistoryItemDuplicateInfo());

希望将来可以帮助某人。

答案 3 :(得分:0)

您可以使用带有自定义java.util.TreeSet的{​​{1}}删除重复项,并将ComparatorInfo考虑在内。

答案 4 :(得分:0)

我会建议你;

  • 使用 long 代替Date对象。
  • 如果您想避免重复,请仅使用Set。你为什么要使用List?如果您需要使用像TreeSet这样的SortedSet或保留像LinkedHashSet这样的订单的Set来保留订单。
  • 您的HistoryItem可以有效吗?你可以构建你的字段,使它们永远不为空吗?
  • 构成hashCode / equals / compareTo的字段应该是不可变的。那些领域可以是最终的吗?如果没有,为什么不呢?

答案 5 :(得分:0)

HashSet被硬编码以使用hashCode()equals()。您可以实现自己的HashSet类,可能是通过无情地复制Java自己的源代码,但这很简单,与任何体面的软件开发规则相矛盾,并且对于Java的源代码许可证可能是非法的(这取决于实际的JDK,例如Sun / Oracle的JDK与OpenJDK)。

但是,您可以使用TreeSet执行操作。 TreeSet通常使用元素的compareTo()方法, hashCode()equals()。此外,可以使用自定义TreeSet实例构建Comparator实例,然后调用该实例进行比较,使您可以自由拥有自己的规则。 compareTo()方法(或Comparator.compare()方法)必须实现订单,这可能比简单的hashCode()更加棘手 - 而且 - {{1}但是,这通常也不难。 equals()有时被称为慢于TreeSet,但实际差异很小,实际上能够以任何方式注意到这种差异需要非常具体的情况。

从概念上讲,HashSet可能存在Comparator的哈希值:具有HashSetHasherAndEqualizer方法的接口int hashCode(Object obj)。 Sun认为不适合包含这样的界面,我不知道为什么。可能他们认为这不会有用。您在另一个答案中引用的“GNU Trove”库提供了这样的界面。

或者,您始终可以使用包装器。您可以存储boolean equals(Object obj1, Object obj2)个实例,每个实例都链接到实际HistoryItem并提供HistoryItemWrapper / HistoryItem方法,而不是在您的辅助集中存储hashCode()个实例需要那套。