Java在自己的声明中引用声明的泛型类型

示例

在声明的泛型类型本身中,如何在方法声明中使用(可能更远的)继承的泛型类型的实例?当您深入研究泛型时,这将是您将面临的问题之一,但仍然是相当普遍的问题。

假设我们有一个DataSeries<T>类型(此处为接口),它定义了一个包含type值的通用数据系列T。当我们想使用例如double值执行很多操作时,直接使用这种类型很麻烦,因此我们定义了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)); // 当心自动装箱
        }
        return DoubleSeries.instance(newdata);
    }

    @Override
    public List<Double> data() {
        return Collections.unmodifiableList(data);
    }
}

如您所见,该add方法被声明为并且编译器很高兴。DoubleSeries add(DoubleSeries values)

如果需要,可以将样式进一步嵌套。