继承 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>
不是。
- 如果将类型参数
X
传递给 ThingHolder
,它必须是 Comparable<X>
的子类型(通过 ThingHolder
的 class 声明) .
- 因此,如果将类型
Thing
传递给 ThingHolder
,它必须是 Comparable<Thing>
的子类型。 (通过用 Thing
替换 X
来遵循先前的陈述。)
Thing
扩展了 Distinct<String>
,因此实现了 Comparable<Distinct<String>>
(通过 Thing
的 class 声明)。
Thing
与 Distinct<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<>();
编译器可以接受。
一般来说,我不喜欢用 ?
来填补空白,因为它通常允许过多的通过,但在这种情况下,我会保留它。
尝试设计一个超类,以确保所有子类本质上都是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>
不是。
- 如果将类型参数
X
传递给ThingHolder
,它必须是Comparable<X>
的子类型(通过ThingHolder
的 class 声明) . - 因此,如果将类型
Thing
传递给ThingHolder
,它必须是Comparable<Thing>
的子类型。 (通过用Thing
替换X
来遵循先前的陈述。) Thing
扩展了Distinct<String>
,因此实现了Comparable<Distinct<String>>
(通过Thing
的 class 声明)。Thing
与Distinct<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<>();
编译器可以接受。
一般来说,我不喜欢用 ?
来填补空白,因为它通常允许过多的通过,但在这种情况下,我会保留它。