比较器的JavaDoc指出
强烈建议(尽管不是必需的)自然顺序与相等一致。
他们还举了一个“奇怪”行为的例子,当<代码>(a.equals(b)
现在,有人能给我举一个例子说明在case(!a.equals(b)中的“奇怪”行为吗
(这是一个更长的故事,为什么这个问题与我有关。而且不是家庭作业)
假设以下API:
final class Foo {
int bar;
Foo(int bar) { this.bar = bar; }
public int hashCode() {
return bar;
}
public boolean equals(Object o) {
return o instanceof Foo && ((Foo)o).bar == bar;
}
}
static Set<Foo> getSetOpaquely() {???}
我不知道这台电视机是从哪里来的,只是我需要用它。
假设我假设这个集合类似于HashSet,并且定义为等于
。
他们还举了一个“奇怪”行为的例子,当<代码>(a.equals(b)
假设我知道
Set<Foo> mySet = getSetOpaquely();
mySet.add(new Foo(1));
System.out.println(mySet.add(new Foo(1));
假设我的惊讶,当这打印
true
,因为它是一个带比较器的TreeSet
(lhs, rhs) -> lhs == rhs ? 0 : 1
现在,有人能给我举一个例子说明在case
(!a.equals(b)中的“奇怪”行为吗
假设我知道
Set<Foo> mySet = getSetOpaquely();
mySet.add(new Foo(102));
System.out.println(mySet.add(new Foo(12));
假设这是一个带有比较器的树集,当它打印出
false
时我感到惊讶
(lhs, rhs) -> Integer.compare(lhs.bar % 10, rhs.bar % 10)
现在,定义与
equals
不一致的顺序并不存在固有的问题。关键是树集的行为可能与集合的文档中指定的行为不同。
这是有明确记录的:
[...]
Set
接口是根据equals操作定义的,但是TreeSet
实例使用其compareTo
(或比较
)方法执行所有元素比较,因此两个元素被视为从集合的角度来看,通过这种方法相等。集合的行为是明确定义的,即使它的顺序与等号不一致;它只是不遵守Set
接口的一般契约。
只要比较器不是黑客,并且你知道它是一个具有特定顺序的树集,你就不会感到惊讶。(如果它是hacky像
(lhs, rhs)-
集合的JDK实现依赖于这样的行为关系。另一个很好的例子是HashSet,它依赖于equals()
和hashCode()
同意。
他们所说的“奇怪”是指“未定义的”——如果这些类与不遵守规则的类一起工作,它们将如何工作是没有定义的。它们可能完美地工作,也可能不完美。但是,如果元素类不遵循javadoc中描述的行为,就不能指望它们正常工作。
这里有一个简单的演示。我们有一个名为Strange
的类,它使用不区分大小写的字符串比较来实现equals
和hashCode
,但实现了区分大小写的compareTo
。
class Strange implements Comparable<Strange> {
final String s;
public Strange(String s) {
this.s = s;
}
@Override
public boolean equals(Object o) {
// Kind of equals - case insensitive.
return (o instanceof Strange) && ((Strange) o).s.equalsIgnoreCase(s);
}
@Override
public int hashCode() {
// Consistent with equals.
return s.toUpperCase().hashCode();
}
@Override
public int compareTo(Strange o) {
// Exact ordering including case - inconsistent with equals.
return s.compareTo(o.s);
}
@Override
public String toString() {
return s;
}
}
public void test() {
Set<Strange> set1 = new HashSet<>();
Set<Strange> set2 = new TreeSet<>();
for (String s : new String[]{"Hello", "hello", "Everyone", "everyone"}) {
Strange strange = new Strange(s);
set1.add(strange);
set2.add(strange);
}
System.out.println("Set1: " + set1);
System.out.println("Set2: " + set2);
}
我们得到-正如你可能期望的那样:
Set1: [Hello, Everyone]
Set2: [Everyone, Hello, everyone, hello]
请参见如何将字符串放入树集
更改结果?这是因为TreeSet
使用compareTo
,而HashSet
使用equals
和hashCode
。这可能会以许多不同的方式(也是最重要的意外方式)破坏事物,因为您不必知道幕后正在使用什么类型的Set
。
这演示了(a.equals(b)
下面的代码是Dave Koelle的AlphanumComparator的编辑版本。编辑包含将空字符串排序到列表末尾或 底部的代码。问题是 为了解决我的问题,我调查了它并找到了诸如比较器没有 等原因; 在正确的位置。我还在Java错误数据库中发现了一条评论,上面写着 java.util.Arrays.sort和java.util.Collections.sort(间接地)使用的排序算法被替换了,新
我已经在类上实现了Comaprable,它给了我比较方法违反了它的总合同!,由于有一些值返回为 null,代码如下 公共静态比较器名称比较器 = 新比较器() {
我有一个类字段,和。我需要使用对它们进行排序,但我得到了一个异常: java.lang.IllegalArgumentException:比较方法违反了它的一般约定! 我的< code>compareTo方法: 请帮我找出compareTo方法中的错误。谢了。
我试图使用比较器基于两个字符串的比较对数组列表进行排序,但我最终使用的比较方法违反了它的一般契约错误。如果字符串中出现空值比较,我该如何处理? 密码 错误
我目前正在Java中对集合进行排序。我收到了错误消息“比较方法违反了它的一般契约”。我也理解这个错误消息,但我(主要)使用Long类型的构建比较方法。所以我不知道,在这种情况下,排序方法仍然违反了契约。这是我的代码: 这里是错误:
我对collection.sort()方法有一些问题。 Java . lang . illegalargumentexception:比较法违反了它的通用契约! 位于Java . util . Tim sort . merge lo(Tim sort . Java:747) at java.util.TimSort.mergeAt(TimSort.java:483) 位于java.util.Tim