【发布时间】:2011-04-29 07:27:32
【问题描述】:
compareTo 方法是否有任何限制,该方法将对象放入标准 java TreeSet(即集合实现为红黑树)?我有
public class RuleTuple implements Comparable {
String head;
String[] rhs;
public String toString() {
StringBuffer b = new StringBuffer();
b.append(head+":");
for( String t: rhs )
b.append(" "+t);
return b.toString();
}
public int compareTo(Object obj) {
RuleTuple src = (RuleTuple)obj;
int cmp = head.compareTo(src.head);
if( cmp!=0 )
return cmp;
if( rhs.length != src.rhs.length )
return rhs.length - src.rhs.length;
for( int i=0; i<rhs.length; i++ )
if( rhs[i].compareTo(src.rhs[i]) != 0 )
return rhs[i].compareTo(src.rhs[i]);
return 0;
}
...
}
我假设任何将对象映射为线性顺序的方法都可以,只要它满足偏序标准:自反性、不对称性和传递性。其中唯一的传递性并不是立即显而易见的,但在我看来,如果对象通过排名标准进行比较,传递性就会遵循。 (我首先比较标题,如果相同,然后比较 rhs 的长度,如果相同,然后比较数组的元素。)
显然,RuleTuple.compareTo() 方法并不一致,因为在删除“test: test[22,33)”时它会按以下顺序遍历树:
test[22,33): 'HAVING' condition <-- comparison#1
test: test[4,19) group_by_clause <-- comparison#2
test: model_clause <-- comparison#3
test: group_by_clause
test:
test: test[22,33)
test: group_by_clause test[22,33) <-- comparison#4; wrong branch!
test: test[4,19) <-- comparison#5
test: group_by_clause model_clause
...
test: test[4,19) group_by_clause model_clause
...
test[4,19): test[5,8) test[8,11)
...
因此,它无法找到并删除树上的对象。我的直觉正确吗?
【问题讨论】:
-
另一个条件是“临时一致性”,即两个对象的比较结果不应该改变,只要它们被用作TreeMap中的键。这意味着您的密钥本质上不应该改变。
-
这可能是关键(双关语)!我确实转换(替代规则)到位。唉,走捷径总是有问题……
-
当
this.head == null而src.head != null时会发生什么?我认为您在切换视点时会收到 NullPointerException。此外,您可能会考虑不调用rhs[i].compareTo(src.rhs[i])两次。 (这只是一个优化,不是你的问题的原因,我不太明白。)除此之外(你应该在这里使用泛型),你的 compareTo 方法看起来不错。 -
为避免一致性问题:从集合/映射中删除规则,更改它,重新添加。
-
我编辑了帖子,因为 null 问题不相关。在按照 Paulo 的建议修复突变问题后,代码似乎运行良好。
标签: java collections