为什么使用 <T 扩展超类>而不仅仅是超类?



早上好,这是从预言机教程中摘录的, 假设我们有

class Shape { /* ... */ }
class Circle extends Shape { /* ... */ }
class Rectangle extends Shape { /* ... */ }

和方法

public static <T extends Shape> void draw(T shape) { /* ... */ }

我的问题如下,你为什么要用<T extends Shape>而不是Shape反正他们不返回完全相同的东西吗?在本例中为形状

对于不返回任何内容的draw方法,也许您是对的,但假设您有一个具有返回值的泛型方法:

public static <T extends Shape> T draw(T shape) { /* ... */ }

现在,使用类型绑定,您可以编写:

Rectangle r = ...
Rectangle r2 = draw(r);
Circle c = ...
Circle c2 = draw(c);

另一方面,如果您将签名更改为

public static Shape draw(Shape shape) { /* ... */ }

您只能写:

Rectangle r = ...
Shape r2 = draw(r);
Circle c = ...
Shape c2 = draw(c);

或者使用显式强制转换(这甚至可能在运行时失败,因为现在draw可以返回任何子类型的Shape(:

Rectangle r = ...
Rectangle r2 = (Rectangle) draw(r);
Circle c = ...
Circle c2 = (Circle) draw(c);

反正他们不返回完全相同的东西吗?

是的,考虑到在这种情况下返回类型是void

<T extends Shape>使该方法能够接受类型ShapeShape的任何子类的输入。

但是,如果您有类似以下内容的内容:

public static <T extends Shape> T draw(T shape) {/* ... */}

那么接收类型可以是ShapeShape的任何子类

如果返回类型是Shape则接收类型只能Shape,而不能是其子类。虽然您可以将返回值从draw()强制转换为适当的类型,但这很容易出错,并且在泛型的帮助下,我们可以消除这种负担。

最新更新