Java 带通配符的模板继承

Java template inheritance with wildcard

在 Java 中,以下代码无法编译:

class Pair <T1> { }

class Real {
    Pair<Real> sqrt() { 
        return null;
    }
}
class Complex extends Real { 
    Pair<Complex> sqrt()  {  
        return null;
    }
}

有道理,因为 Pair<Complex> 没有继承自 Pair<Real>

然而,我惊讶地发现这段代码可以编译:

class Pair <T1> { }

class Real {
    Pair<? extends Real> sqrt() {
        return null;
    }
}

class Complex extends Real {
    Pair<? extends Complex> sqrt()  {
        return null;
    }
}

这似乎暗示 Pair<? extends Complex> 实际上继承自 Pair<? extends Real>

谁能解释一下?这里到底发生了什么?

我认为最好的思考方式是:

您需要在 Complex 中提供一个 return 类型 Pair<T> 的方法,其中 T 可以是从 [=14= 继承的任何东西].您的 Complex 实现将 return 类型要求更改为 Pair<U>,其中 U 可以是从 Complex.

继承的任何内容

然而,由于 Complex 继承自 Real,任何扩展 Complex 的内容也将扩展 Real,因此您仍然提供一种方法来保证 return Pair<T>.

类型

形式化一点:

Pair<? extends Complex> ≡ Pair<? extends Complex extends Real> ≡ Pair<? extends Real>

第一个未编译示例的不同之处在于,您的 Complex 实现实际上限制了 return 类型,因为并非每个 Pair<Real> 都是 Pair<Complex>.

恕我直言,Angelika Langer 为您的问题提供了最好的 explanation (see also subsequent answers),但又困难又详尽。

此外,当不确定两种类型是否真的是子类型和超类型时,以下辅助方法对我很有用。该方法不打算运行。只需显式键入通用参数并查看它是否编译。

public <T,U extends T> void m() {}

this.<Set<Object>,Set<Integer>>m(); -- wont compile
this.<Set<? extends Object>,Set<? extends Integer>>m(); -- compiles