在其自己的声明中引用声明的泛型类型
你如何在声明的泛型类型中的方法声明中使用(可能是进一步的)继承泛型类型的实例?这是你在深入研究泛型时会遇到的问题之一,但仍然是一个相当普遍的问题。
假设我们有一个 DataSeries<T>
类型(这里是接口),它定义了一个包含 T
类型值的通用数据系列。当我们想要用例如双值执行大量操作时直接使用这种类型很麻烦,所以我们定义 DoubleSeries extends DataSeries<Double>
。现在假设,原始 DataSeries<T>
类型有一个方法 add(values)
,它添加另一个相同长度的系列并返回一个新的系列。我们如何在派生类中强制执行 values
的类型和返回的类型为 DoubleSeries
而不是 DataSeries<Double>
?
这个问题可以通过添加一个泛型类型参数来解决,该参数返回并扩展声明的类型(在这里应用于一个接口,但同样代表类):
public interface DataSeries<T, DS extends DataSeries<T, DS>> {
DS add(DS values);
List<T> data();
}
这里 T
代表系列所拥有的数据类型,例如 Double
和 DS
系列本身。现在可以通过用相应的派生类型替换上述参数来轻松实现继承类型(或多个类型),从而产生基于 Double
的具体形式定义:
public interface DoubleSeries extends DataSeries<Double, DoubleSeries> {
static DoubleSeries instance(Collection<Double> data) {
return new DoubleSeriesImpl(data);
}
}
此时甚至 IDE 都会使用正确的类型来实现上面的接口,在一些内容填充后可能如下所示:
class DoubleSeriesImpl implements DoubleSeries {
private final List<Double> data;
DoubleSeriesImpl(Collection<Double> data) {
this.data = new ArrayList<>(data);
}
@Override
public DoubleSeries add(DoubleSeries values) {
List<Double> incoming = values != null ? values.data() : null;
if (incoming == null || incoming.size() != data.size()) {
throw new IllegalArgumentException("bad series");
}
List<Double> newdata = new ArrayList<>(data.size());
for (int i = 0; i < data.size(); i++) {
newdata.add(this.data.get(i) + incoming.get(i)); // beware autoboxing
}
return DoubleSeries.instance(newdata);
}
@Override
public List<Double> data() {
return Collections.unmodifiableList(data);
}
}
正如你所看到的,add
方法被声明为 DoubleSeries add(DoubleSeries values)
并且编译器很高兴。
如果需要,可以进一步嵌套模式。