Java HashSet使用指定方法
我有一个基本类“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);
或者我应该采取另一种方式吗?
I have a basic class 'HistoryItem' like so:
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;
}
}
I am currently using a HashSet to remove duplicates from an ArrayList on the startDate & endDate fields, which is working correctly.
However I also need to remove duplicates on different fields (info & details).
My question is this.
Is there a way to specify a different method which HashSet will use in place of hashCode()?
Something like this:
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);
Or is there another way that I should be doing this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
您可以使用不同的
GetHashCode
实现围绕HistoryItem
创建一个包装器类,然后围绕原始集合中的每个项目创建一个包装器的 HashSet。You can make a wrapper class around
HistoryItem
with a differentGetHashCode
implementation, then make a HashSet of wrappers around each item in the original set.有几件事。首先也是最重要的,如果要重写 hashCode(),则必须重写 equals()。这很重要。其次,如果您正在处理不同的字段,那么您可能应该为每个字段使用不同的 HashSet。所以你可以像这样迭代 Map:
A couple things. First and foremost, you MUST override equals() if you are going to override hashCode(). This is important. Second, if you are dealing with different fields, then you should probably have a different HashSet for each field. So you can iterate over the Map like so:
我最终使用了 GNU Trove 来实现此目的。
需要最少的代码更改。
实现 TObjectHashingStrategy 的新类(包含
HashCode
和Equals
方法)。然后使用 THashSet 对象以及指定的策略来删除重复项。
希望这能够帮助将来的人。
I ended up using GNU Trove for this.
Minimal code change was required.
A new class implementing TObjectHashingStrategy (containing
HashCode
andEquals
methods).Then use the THashSet object with a specified strategy for removing the duplicates.
Hope this is able to help someone out in future.
您可以使用
java.util.TreeSet
和自定义Comparator
来删除重复项,该自定义Comparator
会获取您的Info
和Details
考虑到。You could remove the duplicates using a
java.util.TreeSet
with a customComparator
that takes yourInfo
andDetails
into account.我建议你;
I would suggest you;
HashSet
被硬编码为使用hashCode()
和equals()
。您可以通过无情地复制 Java 自己的源代码来实现您自己的类似 HashSet 的类,但这非常丑陋,与任何像样的软件开发规则集相矛盾,并且对于 Java 源代码来说可能是非法的许可证(这取决于实际的 JDK,例如 Sun/Oracle 的 JDK 与 OpenJDK)。不过,您可以使用
TreeSet
做一些事情。TreeSet
通常使用元素的compareTo()
方法,不使用hashCode()
或equals ()
。此外,可以使用自定义的 Comparator 实例构建 TreeSet 实例,然后调用该实例进行比较,从而使您可以自由地拥有自己的规则。compareTo()
方法(或Comparator.compare()
方法)必须实现一个 order,这可能比简单的hashCode()
-和-equals()
,但这通常也不难。有时据说TreeSet
比HashSet
慢,但实际差异很小,并且需要非常具体的情况才能真正以任何方式注意到这种差异。从概念上讲,
HashSet
可能有一个相当于Comparator
的哈希:带有int hashCode(Object obj)
的接口HasherAndEqualizer
> 和 boolean equals(Object obj1, Object obj2) 方法。 Sun 认为不适合包含这样的接口,我不知道为什么。可能他们认为这没有用。您在另一个答案中引用的“GNU Trove”库提供了这样的接口。或者,您始终可以使用包装器。您可以存储
HistoryItemWrapper
实例,而不是在辅助集中存储HistoryItem
实例,每个实例都链接到实际的HistoryItem
并提供hashCode该集合所需的 ()
/equals()
方法。HashSet
is hardcoded to usehashCode()
andequals()
. You could implement your ownHashSet
-like class, possibly by ruthlessly duplicating Java's own source code, but that's plain ugly, contradicts any decent set of software development rules, and is possibly illegal with regards to Java's source code license (this depends on the actual JDK, e.g. Sun/Oracle's JDK vs OpenJDK).You can do things with
TreeSet
, though.TreeSet
normally uses thecompareTo()
method of the elements, not thehashCode()
orequals()
. Moreover, aTreeSet
instance can be built with a customComparator
instance, which is then invoked to do comparisons, making you free to have your own rules. AcompareTo()
method (or aComparator.compare()
method) must implement an order, which may be a bit trickier than a simplehashCode()
-and-equals()
, but this usually not hard either.TreeSet
is sometimes said to be slower thanHashSet
, but the actual difference is slight and it takes a very specific situation to actually be able to notice that difference in any way.Conceptually, there could be a hash equivalent of
Comparator
forHashSet
: an interfaceHasherAndEqualizer
withint hashCode(Object obj)
andboolean equals(Object obj1, Object obj2)
methods. Sun did not see it fit to include such an interface, I do not know why. Possibly they did not think it would be useful. The "GNU Trove" library that you cite in another answer provides such an interface.Alternatively, you can always use wrappers. Instead of storing
HistoryItem
instances in your secondary set, you can storeHistoryItemWrapper
instances, each linking to an actualHistoryItem
and providing thehashCode()
/equals()
methods you need for that set.