这感觉就像一个非常基本的问题,但它纠缠着我。我希望在两个集合之间获得差异,但似乎我无法这样做,因为set可能包含具有不同Hash和Equals实现的对象。
为了给出我的问题的简化示例,我可以说我有一个由两个类实现的IFoo接口,称之为BasicFoo和ExtendedFoo。它们都描述了相同的物理对象,但ExtendedFoo丰富了BasicFoo缺少的一些额外信息。基本上BasicFoo描述了我的调用者感兴趣的物理对象,我最终会用它来查找模型中相应的ExtendedFoo对象。如果BasicFoo描述相同的物理对象,则可以认为它等于ExtendedFoo。
我有一种方法可以做这样的事情:
public void removeFooInModel(HashSet<IFoo> fooColection){
HashSet<Foo> fooInModel=Model.getFoo();
fooCollection.removeAll(fooInModel);
return;
}
我的问题是我认为它不会一直有效。如果用户传入一个实际上包含BasicFoo对象的fooCollection,并且我的Model.getFoo()方法返回一个实际包含ExtendedFoo的Set,那么它们的equal和hashCode方法会有所不同(ExtendedFoo有更多的状态)比较相等)。尽管我对如何在两个对象之间映射相等和哈希有一个非常清楚的理解,但似乎没有办法强迫我的Set对象使用这些知识。
我想知道的是,当我想要混合和匹配实现时,是否有任何方法可以获得Sets方法的便利,例如removeAll an Contains?
这样做的一种方法是使我的ExtendedFoo和BasicFoo HashCode方法相同,只对在IFoo接口中可用的状态进行散列,并使它们的相等方法仅通过比较IFoo getter来比较不同类的任何IFoo对象方法。但是,如果我后来写了一个扩展IFoo的FooBar对象,我怎么能保证他们也编写与我相同的哈希码方法,所以我的方法仍适用于他们的类?
我可以轻松地解决我自己的问题,因为在一个地方不使用Set这是一个问题。但是,如果我需要HashSet提供的效率增益,其他人会考虑“正确”的解决方案吗?
答案 0 :(得分:1)
不幸的是,你无法说服哈希集比较基本对象和扩展对象的相等性,就好像它们都是基本对象一样。但是,您可以构建一个包含基本对象或扩展对象的包装器对象,并使用基本对象的比较方法来比较这两者。
以下是可能实施的草图:
class FooWrapper {
private final BasicFoo obj;
public FooWrapper(BasicFoo obj) {
this.obj = obj;
}
public BasicFoo getWrapped() {
return obj;
}
public int hashCode() {
// Compute the hash code the way the BasicFoo computes it
}
public boolean equals(Object other) {
// Compare the objects the way the BasicFoo does
}
}
现在,您可以使用BasicFoo
和ExtendedFoo
的混合集合,将它们包装在FooWrapper
中,并将它们放在哈希集中。您可以对集合执行操作,然后通过从包装器集中展开单个BasicFoo
对象来收集结果。