如何在TreeSet中切换排序顺序

时间:2019-02-22 12:53:37

标签: java

我有一个自定义类,在该类中我已经实现了ComparableComparator接口。两者的排序/比较逻辑相反。

以下面的类为例:

class Test implements Comparable<Test>, Comparator<Test>{
    private Integer field;
    public Test(Integer field){this.field = field;}
    @Override
    public int compareTo(Test obj){
       return this.field.compareTo(obj.field);
    }
    @Override
    public int compare(Test t1, Test t2){
       return -t1.compareTo(t2);
    }
    //impl of equals, hashCode and toString omitted for this example
}

因此,默认情况下,当我将Test的对象添加到TreeSet时,它是根据Comparable的实现进行排序的,根据JDK源代码的理解。那么,是否有任何标志/开关可以切换到Comparable实现所表示的排序? 我不想将另一个Comparator传递给TreeSet构造函数。

3 个答案:

答案 0 :(得分:3)

您身边有一个误解:

  • Comparable类具有可以相互比较的对象(例如,要对其进行排序的容器
  • Comparator是用于比较某个类的两个对象的东西。

您无需使类都实现为两者

更糟糕的是:请记住,代码传达了意图:您的类同时实现了两个接口的想法,但是以“相反”的方式实现了反直观。它只会使您的读者感到困惑,并可能导致各种错误,仅因为您的代码所做的事情很少有经验的Java开发人员会期望这样做。永远不要写让读者惊讶的代码(不好的方式)。

请注意,例如,您可以简单地使用Collections.reverseOrder()创建TreeSet!换句话说:您定义了如何比较Test的两个对象这一事实,使您已经可以使用默认的(reversing)比较器。

长话短说:避免“发明”“聪明”的技巧来解决框架行为。相反,学习框架如何“滴答”,并适应它。不要与潮流抗争,顺其自然。

答案 1 :(得分:0)

使用与ComparatorComparable相同的对象是非常不典型的。您可以仅使用两个接口之一来实现两个排序顺序。

Comparator

//Test implements Comparator. reversed() changes order
new TreeSet(new Test().reversed()); 

Comparable

 //elements are Comparable. reverseOrder changes order
new TreeSet(Comparator.reverseOrder());

答案 2 :(得分:0)

如果使用Comparator.comparingInt(Test::getField).reversed()),则不需要为Test类实现自己的比较方法。

完整的示例代码:

static class Test {
    private int field;

    public Test(int field) {
        this.field = field;
    }

    public int getField() {
        return field;
    }
}

public static void main(String[] args) {
    Test test = new Test(5);
    Test test2 = new Test(8);
    TreeSet<Test> tests = new TreeSet<>(Comparator.comparingInt(Test::getField).reversed());
    tests.add(test);
    tests.add(test2);
    for (Test t:tests)
      System.out.println(t.getField());
}

输出:

8
5