Java通用比较器单例

时间:2014-02-23 17:01:56

标签: java generics singleton comparator

有没有办法创建一个实现Comparator的类,只允许创建一个单例实例,或者每个参数化类型只有一个实例失败?

我尝试了几种机制(使用私有构造函数然后使用getInstance方法)但两种机制都不是有效的语法。所以我想知道类型擦除是否意味着不可能依赖于通用Comparator类的单个实例。

目的是避免拥有该类的几十个实例,因为所有实例的行为都相同,因此唯一的实例似乎是可取的。可能吗?如果没有,建议的方法是避免比较器实例的疯狂重复?

编辑:这个问题似乎引起了我正在努力实现的困惑,所以我会在这里粘贴我的一个破坏的尝试。下面的代码是尝试创建一个Map,它只为每个类型T保存一个Comparator实例。这是有效的语法,但我无法调用getInstance方法,因为我无法获取客户端代码中的Class<T>实例。

final class IntervalComparator<T extends Comparable<T>> implements
        Comparator<Interval<T>> {

    // Private constructor. Use the getInstance method instead.
    private IntervalComparator() {
    }

    // Map to hold one instance for each type.
    private static Map<Class, IntervalComparator> cacheMap = new HashMap<>();

    // The only method which returns an instance of this Comparator.
    public static <K extends Comparable<K>> IntervalComparator<K>
            getInstance(Class<K> type) {
        IntervalComparator<K> soleInstance = cacheMap.get(type);
        if(soleInstance == null) {
            soleInstance = new IntervalComparator<>();
            cacheMap.put(type, soleInstance);
        }
        return soleInstance;
    }

    @Override
    public int compare(Interval<T> o1, Interval<T> o2) {
        // ... Comparison code goes here ...
    }
}

客户端代码如下所示:

private Set<Interval<T>> intervalSet;
private IntervalUnion(IntervalUnion.Builder<T> builder) {
    this.intervalSet = new TreeSet<>(new IntervalComparator<T>());
    // ... add Interval<T> objects into intervalSet ...
}

目前每次调用它时都会创建一个new IntervalComparator<T>对象,我认为没有办法将Class<T>传递给getInstance方法。

1 个答案:

答案 0 :(得分:1)

我相信你可以使用一个比较器对象。

我假设您的比较器实现IntervalComparator是无状态的(在某种意义上它没有存储任何字段)。在这种情况下,您始终可以使用相同的代码进行比较。

final class IntervalComparator<T extends Comparable<T>> implements
    Comparator<Interval<T>> {

    // Private constructor. Use the getInstance method instead.
    private IntervalComparator() {
    }

    private static IntervalComparator INSTANCE = new IntervalComparator();

    @SuppressWarnings("unchecked")
    public static <K extends Comparable<K>> IntervalComparator<K> getInstance() {
        return (IntervalComparator<K>)INSTANCE;
    }

    @Override
    public int compare(Interval<T> o1, Interval<T> o2) {
        // ... Comparison code goes here ...
    }
}

您的使用案例如下:

private Set<Interval<T>> intervalSet;

private IntervalUnion() {
this.intervalSet = 
    new TreeSet<Interval<T>>(
      IntervalComparator.<T>getInstance());
// ... add Interval<T> objects into intervalSet ...
}

请注意,多态@SuppressWarnings("unchecked")方法中有一个注释getInstance()。这是为了压制编译器警告,由于Java泛型中的type erasure,无法检查方法中出现的强制转换。

顺便说一下,这种实施有一个突出的有说服力的先例。方法java.util.Collections.emptyList()同样实现:

@SuppressWarnings("unchecked")
public static final List EMPTY_LIST = new EmptyList<>();
// ...

@SuppressWarnings("unchecked")
public static final <T> List<T> emptyList() {
    return (List<T>) EMPTY_LIST;
}

(参见http://www.docjar.com/html/api/java/util/Collections.java.html#3161