【发布时间】:2015-02-24 06:08:50
【问题描述】:
我看到设置比较器的唯一方法是通过 TreeMap 构造函数。例如:
TreeMap myMap = new TreeMap(myComparator);
但是,我想决定在运行时使用哪种类型的比较器。我可以创建多个 TreeMap 或其中一个的新实例,但我发现它会留下更大的内存占用。
有没有办法做到这一点?还是我这边有设计缺陷?
【问题讨论】:
标签: java comparator treemap
我看到设置比较器的唯一方法是通过 TreeMap 构造函数。例如:
TreeMap myMap = new TreeMap(myComparator);
但是,我想决定在运行时使用哪种类型的比较器。我可以创建多个 TreeMap 或其中一个的新实例,但我发现它会留下更大的内存占用。
有没有办法做到这一点?还是我这边有设计缺陷?
【问题讨论】:
标签: java comparator treemap
我建议您推迟创建TreeMap,直到您知道哪个Comparator 是合适的。如果这是不可能的(例如,因为您需要使用对 TreeMap 的引用来初始化其他对象),请考虑将 TreeMap 隐藏在将延迟初始化它的方法或类后面,或者使用工厂模式。
如果这也是不可能的,请使用您自己的 Comparator 实现初始化 TreeMap,并在那里做出决定(在您开始向 TreeMap 添加项目之前,不会调用 compareTo())。如果你走这条路,你必须非常小心在你开始向树中添加项目之后不要改变比较器的行为!
至于为什么TreeMap(或大多数其他采用Comparator 的集合)不允许您更改Comparator,请参阅@Evgeniy Dorofeev 的答案。
【讨论】:
TreeMap 被许多地方引用(都需要更新),它可能会变得混乱。
TreeMap 不允许更改 Comparator,因为内部树结构依赖于 Comparator,更改它会使内部树无效。
【讨论】:
你可以这样做:
class MyCompartor<T> implements Comparator<T> {
Comparator<T> changeableComparator;
public void setComparator(Comparator<T> comparator) {
this.changeableComparator = comparator;
}
@Override
public int compare(T o1, T o2) {
return changeableComparator.compare(o1, o2);
}
}
但这太疯狂了。您不能也不得在运行时更改TreeMap 的Comparator。树不会根据新的Comparator 重新组织自己。
相反,为每个新的Comparator 创建一个新的TreeMap(也就是说,如果在其他人建议的比较类型已知时您无法初始化映射)。
或者,子类化 TreeMap 并使用上述可更改的Comparator 添加一个重组方法,但实际上这与创建一个新的TreeMap 几乎相同(性能方面)。您唯一要消除的是内存分配。
【讨论】:
您可以通过以下方式实现您的比较器:
//first impl
final Comparator<String> first = new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return 0;
}
};
//second impl
final Comparator<String> second = new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return 0;
}
};
Comparator<String> inst=first;
//Treemap initialization
TreeMap<String, String> t = new TreeMap<>(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
//call of the impl
return inst.compare(o1, o2);
}
});
.....
//switch during runtime
inst = second;
....
【讨论】: