继承 Comparable 与泛型

Inheriting Comparable with generics

尝试设计一个超类,以确保所有子类本质上都是Comparable

/**
 * A base class implementing Comparable with itself by delegation.
 * @param <T> - The type being wrapped.
 */
static class Distinct<T extends Comparable<T>> implements Comparable<Distinct<T>> {
    final T it;
    public Distinct(T it) {
        this.it = it;
    }
    @Override
    public int compareTo(Distinct<T> o) {
        return it.compareTo(o.it);
    }
}
/**
 * A set of distinct items.
 *
 * @param <T>
 */
static class ThingHolder<T extends Comparable<T>> {
    final Set<T> things;
    public ThingHolder() {
        this.things = new TreeSet<>();
    }
}
/**
 * A sample real thing.
 */
static class Thing extends Distinct<String> {
    public Thing(String it) {
        super(it);
    }
}
// This doesn't work - Why?
final ThingHolder<Thing> yz = new ThingHolder<>();

我得到的错误是:

com/oldcurmudgeon/test/Test.java:[70,22] error: type argument Thing is not within bounds of type-variable T
  where T is a type-variable:
    T extends Comparable<T> declared in class ThingHolder

为什么这不起作用?可以吗?

只需将 ThingHolder class 签名更改为:

static class ThingHolder<T extends Comparable> {
       ...    
}

即从 Comparable 中删除 <T>,没有必要。

class ThingHolder<T extends Comparable<T>> 声明 事物 T 必须与其自身具有可比性,但 class Thing extends Distinct<String> 不是。

  1. 如果将类型参数 X 传递给 ThingHolder,它必须是 Comparable<X> 的子类型(通过 ThingHolder 的 class 声明) .
  2. 因此,如果将类型 Thing 传递给 ThingHolder,它必须是 Comparable<Thing> 的子类型。 (通过用 Thing 替换 X 来遵循先前的陈述。)
  3. Thing 扩展了 Distinct<String>,因此实现了 Comparable<Distinct<String>>(通过 Thing 的 class 声明)。
  4. ThingDistinct<String> 不是同一类型 - 尽管它是子类型 - 因此类型匹配失败。

您可以通过如下调整 ThingHolder 的 class 声明来解决此问题:

class ThingHolder<T extends Comparable<? super T>> {
    ...
}

一些研究和抨击提出了 this suggestion

In general, if you have an API that only uses a type parameter T as an argument, its uses should take advantage of lower bounded wildcards (? super T).

一些修补(添加 ? super T)以稍微放宽限制离开:

/**
 * A set of distinct items.
 *
 * Don't like the <?> in there but a <T> is not accepted.
 *
 * @param <T>
 */
static class ThingHolder<T extends Comparable<? super T>> {

    final Set<T> things = new TreeSet<>();

}

final ThingHolder<Thing> holder = new ThingHolder<>();

编译器可以接受。

一般来说,我不喜欢用 ? 来填补空白,因为它通常允许过多的通过,但在这种情况下,我会保留它。