早上好,这是从预言机教程中摘录的, 假设我们有
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>
使该方法能够接受类型Shape
或Shape
的任何子类的输入。
但是,如果您有类似以下内容的内容:
public static <T extends Shape> T draw(T shape) {/* ... */}
那么接收类型可以是Shape
或Shape
的任何子类。
如果返回类型是Shape
则接收类型只能是Shape
,而不能是其子类。虽然您可以将返回值从draw()
强制转换为适当的类型,但这很容易出错,并且在泛型的帮助下,我们可以消除这种负担。