简体   繁体   English

继承与泛型相媲美

[英]Inheriting Comparable with generics

Trying to design a superclass that ensures all sub-classes are inherently Comparable . 试图设计一个超类,确保所有子类本身都是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<>();

The error I get reads: 我得到的错误是:

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

Why is this not working? 为什么这不起作用? Can it be done? 可以吗?

  1. If you pass a type argument X to ThingHolder it has to be a subtype of Comparable<X> (by the class declaration of ThingHolder ). 如果将类型参数X传递给ThingHolder它必须是Comparable<X>的子类型(通过ThingHolder的类声明)。
  2. So, if you pass the type Thing to ThingHolder it has to be a subtype of Comparable<Thing> . 因此,如果将Thing类型传递给ThingHolder它必须是Comparable<Thing>的子类型。 (Follows from the previous statement by substitution of Thing for X .) (根据之前的陈述,将Thing替换为X
  3. Thing extends Distinct<String> and therefore implements Comparable<Distinct<String>> (by the class declaration of Thing ). Thing扩展了Distinct<String> ,因此实现了Comparable<Distinct<String>> (通过Thing的类声明)。
  4. Thing is not the same type as Distinct<String> - although it's a subtype - and therefore type matching fails. ThingDistinct<String>类型Distinct<String> - 尽管它是一个子类型 - 因此类型匹配失败。

You could fix this by adjusting the class declaration of ThingHolder as follows: 你可以通过调整ThingHolder的类声明来解决这个ThingHolder ,如下所示:

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

Some research and head-bashing brought up 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). 通常,如果您的API只使用类型参数T作为参数,则其使用应该利用较低的有界通配符(?super T)。

Some tinkering (adding ? super T ) to slightly relax the restrictions leaves: 一些修补(添加? 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<>();

and this is acceptable to the compiler. 这对编译器来说是可以接受的。

Generally I don't like using ? 一般我不喜欢用? to paper over the gaps because it usually allows too much through but in this case I will leave it at that. 为了填补空白,因为它通常允许过多,但在这种情况下,我会留下它。

Just change ThingHolder class signature to: 只需将ThingHolder类签名更改为:

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

Ie remove <T> from Comparable , it isn't necessary. 即从Comparable删除<T> ,没有必要。

class ThingHolder<T extends Comparable<T>>声明事物 T必须与自身相当,但class Thing extends Distinct<String>不是。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM