我有一个代表一列的类。它有一个比较器,看起来像这样:
class Column
{
int xposition;
int usage;
@Override
public int compare(Object arg0, Object arg1)
{
// sort logic
}
}
我有TreeSet
个Column
个。我想先按TreeSet
排序x-position
,然后按usage
排序。
我尝试创建一个超级类,例如Column2
,它扩展了Column
并具有不同的compare
方法。然而,这使得从Column
转换为Column2
(反之亦然)非常难看。我还想到Column
中的一个标志,指示如何进行排序,但这意味着修改所有对象以更改排序标准。
有没有更好的方法呢?
答案 0 :(得分:4)
我会在一组外部Comparator
中使用比较逻辑来表示您拥有的不同排序案例,然后在您想要更改排序时创建一个新的TreeSet
:
class Column
{
int xposition;
int usage;
public static final Comparator<Column> SortByX = new Comparator<Column>() {
@Override
public int compare(Column c1, Column c2)
{
return Integer.compare(c1.xposition, c2.xposition);
}
};
public static final Comparator<Column> SortByUsage = new Comparator<Column>() {
@Override
public int compare(Column c1, Column c2)
{
return Integer.compare(c1.usage, c2.usage);
}
};
}
TreeSet<Column> cols = new TreeSet<>(Column.SortByX);
然后,要更改排序:
TreeSet<Column> updated = new TreeSet<>(Column.SortByUsage);
updated.addAll(cols);
cols = updated;
如果在多线程环境中发生这种情况,则进行适当的同步。
无论您做什么,都不要使用可变状态更改对象Comparator
的行为。如果你这样做,你可能很容易失去跟踪&#34;将对象放入像TreeSet
这样的集合之后的对象。
答案 1 :(得分:0)
您想要实现的目标似乎是战略模式的经典用例(例如Real World Example of the Strategy Pattern)
本质上,您希望将此比较函数打包成可以放在列类的单独字段中的东西 - 具有实现Comparable的单个函数的普通类将起作用。然后,您的列只会将调用委托给该字段中存储的任何比较器。
答案 2 :(得分:0)
这是Guava&#39; ComparisionChain的确切用例:
采取的示例from here:
public int compareTo(Foo that) {
return ComparisonChain.start()
.compare(this.xposition, that.xposition)
.compare(this.usage, that.usage)
.result();
}
答案 3 :(得分:0)
就像Sean Bright回答一样,我使用外部Comparator
,如果你正在使用Java 8,你可以很容易地做到:
public static final Comparator<Foobar> NAME_THEN_AGE =
Comparators.comparing(Foobar::getName, String.CASE_INSENSITIVE_ORDER)
.thenComparing(Foobar::getAge)
;
....
TreeSet<Foobar> foobar = new TreeSet<>(NAME_THEN_AGE);
但是,更好的是,在子类上覆盖Comparable
通常是一个坏主意 - 也许它应该在父类上final
或者应该创建一个受保护的compareTo0(A)
做共同的工作(避免通过父类比较对象)。
有理由这样做,其中一个如下(来自Comparable.compareTo的Javadoc):
实现者必须确保sgn(x.compareTo(y))== -sgn(y.compareTo(x))表示所有x和y。 (这意味着如果y.compareTo(x)抛出一个x.compareTo(y)必须抛出异常 异常。)
我们假设您class B
和C
延长A
而A实施Comparable<A>
:
class A implements Comparable<A> {
@Override
public int compareTo(A other) {return ...;}
}
class B extends A {
@Override
public int compareTo(A other) {return compareToAsB(((B)other));}
}
class C extends A {
@Override
public int compareTo(A other) {return compareToAsC(((C)other));}
}
A::compareTo
返回的内容并不重要。 compareToAsB
和compareToAsC
都没有。
问题在于:
A a = ...;
B b = ...;
C c = ...;
a.compareTo(b); // ok
a.compareTo(c); // ok
b.compareTo(a); // ko ClassCastException
b.compareTo(c); // ko ClassCastException
c.compareTo(a); // ko ClassCastException
c.compareTo(b); // ko ClassCastException
如javadoc所引用,a.compareTo(b)
应该抛出ClassCastException
。
此外,Java代码(Collections.sort
)中还有一部分需要确保 sgn(x.compareTo(y))== -sgn(y.compareTo(x))对于所有x和y 。