繁体   English   中英

HashSet / HashMap等效的TreeSet / TreeMap(自定义哈希)

[英]TreeSet/TreeMap equivalent for HashSet/HashMap (custom hasher)

TreeSet有一个带比较器的构造函数,这意味着即使您存储的对象本身不是Comparable对象,您也可以提供自定义比较器。

是否有类似的无序集实现? (例如, HashSet<T>的替代方法是采用“hasher”对象来计算对象T的equals()hashCode() ,这些对象可能与对象自己的实现不同?)

C ++ std::hash_set为您提供了这个,只是想知道是否有适合Java的东西。


编辑:@Max提出了一个关于equals()的良好技术观点 - 足够公平; 通过Map.containsKey()TreeMapHashMapMap.containsKey() 但是否有其他众所周知的数据结构可以通过自定义哈希来组织?

不, Collections规范不支持具有“hasher”对象。 您当然可以实现自己的集合来支持这一点,但另一种方法是将Hasher视为您存储在HashSet的包装对象。

Set<HasherWrapper<Foo>> set = new HashSet<HasherWrapper<Foo>>();
set.add(new HasherWrapper(foo));
...

然后包装类看起来像:

private class HasherWrapper<T> {
    T wrappedObject;
    public HasherWrapper(T wrappedObject) {
        this.wrappedObject = wrappedObject;
    }
    @Override
    public int hashCode() {
        // special hash code calculations go here
    }
    @Override
    public boolean equals(Object obj) {
        // special equals code calculations go here
    }
}

标准库中没有这样的实现,但它不会阻止您自己滚动。 这是我经常想要拥有的东西。

请参阅http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4771660 ,原因如下:

我们想避免复杂性。 在收集框架设计时,我们认真地接受了这个概念,但拒绝了它。 功率重量比似乎很低。 我们觉得平等是你想要的95%的时间; ==,4%; 和别的东西1%。 当等式谓词不同时,为批量操作编写合理的合同是非常棘手的。

不,没有,也没有规范。 而且,你误解了TreeSet使用它的Comparator

来自TreeSet Javadoc

请注意,如果要正确实现Set接口,则由set维护的排序(无论是否提供显式比较器)必须与equals一致。 (有关与equals一致的精确定义,请参阅Comparable或Comparator。)这是因为Set接口是根据equals操作定义的,但TreeSet实例使用compareTo(或compare)方法执行所有元素比较,因此从集合的角度来看,通过这种方法被认为相等的元素是相等的。 集合的行为即使其排序与equals不一致也是明确定义的; 它只是不遵守Set接口的一般合同。

来自Comparable javadoc

当且仅当e1.compareTo(e2)== 0与c1的每个e1和e2的e1.equals(e2)具有相同的布尔值时,C类的自然排序被认为与equals一致。 null不是任何类的实例,并且即使e.equals(null)返回false,e.compareTo(null)也应抛出NullPointerException。

来自收藏夹javadoc

boolean contains(Object o)

如果此collection包含指定的元素,则返回true。 更正式地,当且仅当此集合包含至少一个元素e时才返回true(o == null?e == null:o.equals(e))。

因此,通过规范,不能有任何类实现Collection<E>接口并且完全依赖于某些外部Comparator样式的对象来插入对象。 所有集合应使用Object类的equals方法来验证对象是否已插入。

绝对没有类似的东西, hashcode()equals()定义了对象的属性,不应该更改。 它们定义了使对象彼此相等的原因,并且这不应该从一个集合到另一个集合。 做你正在谈论的唯一方法是子类化对象并编写一个新的hashcode()equals() ,如果子类有一个应该添加的定义变量,这只会有意义。超类' hashcode()equals() 我知道这可能不是你的目标,但我希望这会有所帮助。 如果你想要更多地解释你的推理,那么如果存在一个更好的解决方案可能会有所帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM