如何区分Sorted集合中的两个equals对象?

Seb*_*ber 3 java apache-commons guava

我可能错了,但对我来说,我们可以为一个对象重写equals,以便你认为它们有意义地等于.映射中的所有条目都具有不同的键,并且集合中的所有条目都具有不同的值(不是有意义的等于)

但是在使用TreeMap或TreeSet时,您可以提供比较器.我注意到,当提供比较器时,绕过对象的equals方法,并且当比较器返回0时,两个objets被认为是等于.因此,我们有2个对象但是在map keyset或set中,只保留一个.

我想知道是否有可能使用已排序的集合来区分两个不同的实例.

这是一个简单的示例:

public static void main(String[] args) {
    TreeSet<String> set = new TreeSet<String>();
    String s1 = new String("toto");
    String s2 = new String("toto");
    System.out.println(s1 == s2);
    set.add(s1);
    set.add(s2);
    System.out.println(set.size());
}
Run Code Online (Sandbox Code Playgroud)

请注意,使用新的String("xxx")会绕过String池的使用,因此s1!= s2.我想知道如何实现比较器,使设置大小为2而不是1.

主要问题是:对于相同String值的两个不同实例,我如何在比较器中返回一些东西!= 0?

请注意,我希望比较器遵守规则:

比较它的两个参数的顺序.返回负整数,零或正整数,因为第一个参数小于,等于或大于第二个参数.实现者必须确保所有x和y的sgn(compare(x,y))== -sgn(compare(y,x)).(这意味着当且仅当compare(y,x)抛出异常时,compare(x,y)必须抛出异常.)

实现者还必须确保关系是传递的:((compare(x,y)> 0)&&(compare(y,z)> 0))表示compare(x,z)> 0.

最后,实现者必须确保compare(x,y)== 0意味着所有z的sgn(compare(x,z))== sgn(compare(y,z)).

通常情况是这样,但并非严格要求(compare(x,y)== 0)==(x.equals(y)).一般来说,任何违反此条件的比较器都应清楚地表明这一事实.推荐的语言是"注意:这个比较器强加了与equals不一致的排序."

我可以用一个技巧:

public int compare(String s1,String s2) {
  if s1.equals(s2) { return -1 }
  ...
}
Run Code Online (Sandbox Code Playgroud)

它似乎工作正常,但自从比较(s1,s2)后规则不受尊重!= -compare(s2,s1)

那么这个问题有什么优雅的解决方案吗?


编辑:对于那些想知道为什么我问这样的事情的人.好奇心比任何现实生活中的问题更重要.

但我已经处于这样的情况,虽然有关此问题的解决方案:

想象一下你有:

class Label {
  String label;
}
Run Code Online (Sandbox Code Playgroud)

对于每个标签,您都有一个关联的String值.现在如果你想要一个map,label-> value怎么办?但是现在如果你希望能够拥有两个与地图键相同的标签呢?Ex"label"(ref1) - > value1"label"(ref2) - > value2您可以实现equals,以便两个不同的Label实例不等于 - >我认为它适用于HashMap.

但是,如果您希望能够按字母顺序对这些Label对象进行排序,该怎么办?您需要提供可比较的比较器或工具.但是,我们如何才能区分具有相同标签的2个标签?我们必须!compare(ref1,ref2)不能返回0.但是它应该返回-1还是1?我们可以比较内存地址或类似的东西来做出这样的决定,但我认为这在Java中是不可能的......

Sim*_*son 6

如果您正在使用Guava,您可以使用Ordering.arbitrary(),这将对元素施加额外的顺序,这些元素在VM的生命周期内保持一致.您可以使用它以一致的方式打破比较器中的关系.

但是,您可能使用了错误的数据结构.您是否考虑使用Multiset(例如TreeMultiset),允许添加多个实例?

  • 这很有趣.它使用System.identityHashCode()作为第一次传递,然后如果存在冲突,它会为每个看到的新实例维护一个UID列表.请参阅http://guava-libraries.googlecode.com/svn-history/r311/trunk/javadoc/src-html/com/google/common/collect/Ordering.html (2认同)