TreeSet未按预期由自定义Comparator排序

时间:2018-04-02 15:59:19

标签: java groovy comparator treeset

我有一个用类填充的TreeSet。我希望按照它们的继承顺序排列这些,只是按字母顺序排列(以创建一个常量顺序)。但由于某种原因,如果要添加的类的顺序不正确,则会导致类无法正确排序。

这是我的比较者:

class OrderedComparator implements Comparator<Class<?>> {

    @Override
    int compare(Class<?> clazz1, Class<?> clazz2) {
        if (clazz1 == clazz2) {
            return 0
        } else if (clazz1.isAssignableFrom(clazz2)) {
            return -1
        } else if (clazz2.isAssignableFrom(clazz1)) {
            return 1
        } else {
            return clazz1.canonicalName.compareTo(clazz2.canonicalName)
        }
    }
}

以下是失败测试的示例:

def 'OrderedSet is ordered in inheritence order, classes added multiple times'() {
    setup:
    Set<Class<?>> orderedSet = new TreeSet<>(new OrderedComparator())
    when:
    orderedSet.add(com.benjaminsproule.swagger.gradleplugin.test.springmvc.ExtendedTestResourceWithClassAnnotation.class)
    orderedSet.add(com.benjaminsproule.swagger.gradleplugin.test.springmvc.TestResourceWithClassAnnotation.class)
    orderedSet.add(com.benjaminsproule.swagger.gradleplugin.test.jaxrs.ExtendedTestResourceWithoutClassAnnotation.class)
    orderedSet.add(com.benjaminsproule.swagger.gradleplugin.test.jaxrs.TestResourceWithClassAnnotation.class)
    orderedSet.add(com.benjaminsproule.swagger.gradleplugin.test.springmvc.TestResourceWithoutClassAnnotation.class)
    orderedSet.add(com.benjaminsproule.swagger.gradleplugin.test.jaxrs.ExtendedTestResourceWithClassAnnotation.class)
    orderedSet.add(com.benjaminsproule.swagger.gradleplugin.test.jaxrs.TestResourceWithoutClassAnnotation.class)
    orderedSet.add(com.benjaminsproule.swagger.gradleplugin.test.springmvc.ExtendedTestResourceWithoutClassAnnotation.class)
    orderedSet.add(com.benjaminsproule.swagger.gradleplugin.test.jaxrs.TestResourceWithClassAnnotation.class)
    orderedSet.add(com.benjaminsproule.swagger.gradleplugin.test.jaxrs.ExtendedTestResourceWithClassAnnotation.class)
    then:
    assert orderedSet[0] == com.benjaminsproule.swagger.gradleplugin.test.jaxrs.TestResourceWithClassAnnotation.class
    assert orderedSet[1] == com.benjaminsproule.swagger.gradleplugin.test.jaxrs.ExtendedTestResourceWithClassAnnotation.class
    assert orderedSet[2] == com.benjaminsproule.swagger.gradleplugin.test.jaxrs.TestResourceWithoutClassAnnotation.class
    assert orderedSet[3] == com.benjaminsproule.swagger.gradleplugin.test.jaxrs.ExtendedTestResourceWithoutClassAnnotation.class
    assert orderedSet[4] == com.benjaminsproule.swagger.gradleplugin.test.springmvc.TestResourceWithClassAnnotation.class
    assert orderedSet[5] == com.benjaminsproule.swagger.gradleplugin.test.springmvc.ExtendedTestResourceWithClassAnnotation.class
    assert orderedSet[6] == com.benjaminsproule.swagger.gradleplugin.test.springmvc.TestResourceWithoutClassAnnotation.class
    assert orderedSet[7] == com.benjaminsproule.swagger.gradleplugin.test.springmvc.ExtendedTestResourceWithoutClassAnnotation.class
}

orderedSet的实际值:

0 = {Class@1272} "class com.benjaminsproule.swagger.gradleplugin.test.jaxrs.ExtendedTestResourceWithClassAnnotation"
1 = {Class@1474} "class com.benjaminsproule.swagger.gradleplugin.test.jaxrs.TestResourceWithoutClassAnnotation"
2 = {Class@1475} "class com.benjaminsproule.swagger.gradleplugin.test.jaxrs.ExtendedTestResourceWithoutClassAnnotation"
3 = {Class@1271} "class com.benjaminsproule.swagger.gradleplugin.test.jaxrs.TestResourceWithClassAnnotation"
4 = {Class@1480} "class com.benjaminsproule.swagger.gradleplugin.test.springmvc.ExtendedTestResourceWithoutClassAnnotation"
5 = {Class@1286} "class com.benjaminsproule.swagger.gradleplugin.test.springmvc.TestResourceWithClassAnnotation"
6 = {Class@1287} "class com.benjaminsproule.swagger.gradleplugin.test.springmvc.ExtendedTestResourceWithClassAnnotation"
7 = {Class@1476} "class com.benjaminsproule.swagger.gradleplugin.test.springmvc.TestResourceWithoutClassAnnotation"

我的期望更像是:

0 = {Class@1271} "class com.benjaminsproule.swagger.gradleplugin.test.jaxrs.TestResourceWithClassAnnotation"
1 = {Class@1272} "class com.benjaminsproule.swagger.gradleplugin.test.jaxrs.ExtendedTestResourceWithClassAnnotation"
2 = {Class@1474} "class com.benjaminsproule.swagger.gradleplugin.test.jaxrs.TestResourceWithoutClassAnnotation"
3 = {Class@1475} "class com.benjaminsproule.swagger.gradleplugin.test.jaxrs.ExtendedTestResourceWithoutClassAnnotation"
4 = {Class@1286} "class com.benjaminsproule.swagger.gradleplugin.test.springmvc.TestResourceWithClassAnnotation"
5 = {Class@1287} "class com.benjaminsproule.swagger.gradleplugin.test.springmvc.ExtendedTestResourceWithClassAnnotation"
6 = {Class@1476} "class com.benjaminsproule.swagger.gradleplugin.test.springmvc.TestResourceWithoutClassAnnotation"
7 = {Class@1480} "class com.benjaminsproule.swagger.gradleplugin.test.springmvc.ExtendedTestResourceWithoutClassAnnotation"

我在调试时注意到,并非每个项目都相互比较。

2 个答案:

答案 0 :(得分:3)

考虑这些课程

class A extends C {}

class B {}

class C {}

此处A出现在B之前(两者都不是另一个的子类,因此按字母顺序排列)。

同样B出现在C之前。

如果您的Comparator具有传递性,则意味着A出现在C之前。然而,

compare(A.class, C.class) == 1   // Because A is a subclass of C

意味着A大于&#34;大于&#34; C

一旦开始尝试使用无效比较器进行排序,就不会指定行为。

答案 1 :(得分:0)

尝试改变条件:

if (clazz1 == clazz2) {
    return 0;
} else if (clazz1.isAssignableFrom(clazz2)) {
    return 1; // this changed
} else if (clazz2.isAssignableFrom(clazz1)) {
    return -1; // this changed
} else {
    return clazz1.getCanonicalName().compareTo(clazz2.getCanonicalName());
}

因为我在Test *和ExtendedTest *类中看到了期望与实际排序之间的反转。