【发布时间】:2012-05-06 03:34:03
【问题描述】:
我可能错了,但对我来说,我们可以为一个对象覆盖等于,这样你就认为它们有意义地等于。 映射中的所有条目都有不同的键,集合中的所有条目都有不同的值(没有意义地等于)
但是当使用 TreeMap 或 TreeSet 时,您可以提供一个比较器。 我注意到,当提供比较器时,对象的 equals 方法被绕过,当比较器返回 0 时,两个对象被认为是相等的。 因此,我们有 2 个对象,但在映射键集或集合中,只保留了一个。
我想知道是否有可能使用排序集合来区分两个不同的实例。
这是一个简单的示例:
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());
}
请注意,使用 new String("xxx") 会绕过字符串池的使用,因此 s1 != s2。 我想知道如何实现一个比较器,以便设置大小为 2 而不是 1。
主要问题是:对于相同字符串值的两个不同实例,我如何在比较器中返回 != 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))。一般来说,任何违反此条件的比较器都应清楚地表明这一事实。推荐的语言是“注意:这个比较器强加了与等号不一致的顺序。”
我可以使用这样的技巧:
public int compare(String s1,String s2) {
if s1.equals(s2) { return -1 }
...
}
它似乎工作正常,但由于 compare(s1,s2) != -compare(s2,s1) 没有遵守规则
那么这个问题有什么优雅的解决方案吗?
编辑:对于那些想知道我为什么要问这样的事情的人。这更多是出于好奇,而不是任何现实生活中的问题。
但是我已经遇到过这样的情况,虽然关于这个问题的解决方案:
想象一下你有:
class Label {
String label;
}
对于每个标签,您都有一个关联的字符串值。 现在,如果你想要一个地图,标签-> 值怎么办。 但是现在,如果您希望能够拥有与地图键相同的两倍标签怎么办? 前任 “标签”(ref1)-> value1 “标签”(ref2)-> value2 您可以实现等于,以便两个不同的 Label 实例不等于 -> 我认为它适用于 HashMap。
但是,如果您希望能够按字母顺序对这些 Label 对象进行排序呢? 您需要提供比较器或实现可比较。 但是我们如何才能区分具有相同标签的 2 个标签呢? 我们必须! compare(ref1,ref2) 不能返回 0。但它应该返回 -1 还是 1 ? 我们可以比较内存地址或类似的东西来做出这样的决定,但我认为这在 Java 中是不可能的......
【问题讨论】:
-
我的意见是,在您的情况下,您不应该使用字符串作为标识符(地图的键),因为它们不是真正的标识符。如果你有一个字符串
"label",你怎么知道你想要两个Label对象中的哪一个? -
这只是一个例子,但实际上我不仅有“标签”,而且我必须分开引用
标签: java guava apache-commons