在其自己的宣告中引用宣告的泛型型別
你如何在宣告的泛型型別中的方法宣告中使用(可能是進一步的)繼承泛型型別的例項?這是你在深入研究泛型時會遇到的問題之一,但仍然是一個相當普遍的問題。
假設我們有一個 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)
並且編譯器很高興。
如果需要,可以進一步巢狀模式。