假设定义了以下类:
class Shape { }
class Circle extends Shape { }
class Rectangle extends Shape { } // 1
您可以编写一个通用方法来绘制不同的形状:
public static <T extends Shape> void draw(T shape) { } // 2
Java编译器将T替换为Shape:
public static void draw(Shape shape) { } // 3
我的问题是,如果我们在课堂上直接定义// 3,那么我们仍然可以在// 3处将Shape
,Circle
和Rectangle
引用传递给方法。那么为什么我们需要用类型参数<T extends Shape>
编写// 2泛型方法,它与// 3完全相同?
您可以使用相同的示例来引用此链接:http://docs.oracle.com/javase/tutorial/java/generics/genMethods.html
答案 0 :(得分:7)
您可能需要也可能不需要它。如果您的方法必须处理T
类型的其他必须与T extends Shape
类型完全匹配的对象,则需要它,例如:
public static <T extends Shape> void drawWithShadow(T shape, Class<T> shapeClass) {
// The shadow must be the same shape as what's passed in
T shadow = shapeClass.newInstance();
// Set the shadow's properties to from the shape...
shadow.draw(); // First, draw the shadow
shape.draw(); // Now draw the shape on top of it
}
在上面,传递Shape
是不够的,因为我们无法制作完全相同类型的阴影。
如果没有这样的要求,简单的Shape
就足够了。
答案 1 :(得分:2)
在这种特殊情况下,您不需要通用方法。
但是你可以在泛型方法中做更多的事情,而不是在其参数上调用动态链接的方法。
例如,您可能有一个接受并返回T元素集合的泛型方法。按类型对其进行参数化可以让您在多种集合类型上使用它。
通用方法有用的其他示例包含在此Java tutorial中。
答案 2 :(得分:2)
在您的示例中,// 3确实与// 2相同。但在其他用例中,泛型类型可能很有用:
您希望从方法返回值,与参数类型相同
您有2个或更多参数,并希望设置限制,它们必须属于同一类型
答案 3 :(得分:1)
主要的兴趣是您可以将方法的使用限制在代码的不同部分中的特定类型的形状。
在某些时候,您可能希望将其参数化为仅绘制Rectangle
而在另一个地方仅绘制Circle
,这将在编译时检查,即使在运行时,您将传递某种类型的东西Shape
答案 4 :(得分:1)
区别在于你正在使用的多态性。
在通用情况下,您使用的是参数多态,而在第二种情况下,您正在使用多态通过子类型。实际上,你的第一个案例使用了这两种多态性。
现在,它们在某些方面可能相似,但它们并不相同。一个实际的例子:
List<Shape> shapes;
List<T extends Shape> specificShapes;
你可以看到,在第一种情况下,没有类型参数,我无法管理Shape的特定子类型的列表,我只能管理一个异形的形状列表,但我无法强制任何特定的一个就可以了。所以我没有任何编译时间禁止我在Triangle
添加Rectangle
和shapes
。
class ShapeDecorator {
private Shape shape;
..
Shape get() { return shape; }
}
class ShapeDecorator<T extends Shape> {
private T shape;
T get() { return shape; }
}
这是另一个例子,在这种情况下你可以编写一个通用的装饰器,它能够返回一个类型T,而不需要任何强制转换。这在将公共祖先作为子类型不足的许多情况下都很有用。